Restructuring the python code and libs - first stage.
3e5a4e681xMPdF9xCMwpyfuYMySU5g linux-2.4.26-xen-sparse/mm/mremap.c
409ba2e7akOFqQUg6Qyg2s28xcXiMg linux-2.4.26-xen-sparse/mm/page_alloc.c
3e5a4e683HKVU-sxtagrDasRB8eBVw linux-2.4.26-xen-sparse/mm/swapfile.c
+40e1b09db5mN69Ijj0X_Eol-S7dXiw tools/Make.defs
3f776bd1Hy9rn69ntXBhPReUFw9IEA tools/Makefile
401d7e160vaxMBAUSLSicuZ7AQjJ3w tools/examples/Makefile
401d7e16UgeqroJQTIhwkrDVkoWgZQ tools/examples/README
405ff55dawQyCHFEnJ067ChPRoXBBA tools/examples/init.d/xend
40278d94cIUWl2eRgnwZtr4hTyWT1Q tools/examples/init.d/xendomains
40278d91ZjLhxdjjrGe8HEdwHLj5xQ tools/examples/netbsd
+40e15b7edWEtBf_oe3eBwGKuh1dyzQ tools/examples/vifctl
401d7e16NpnVrFSsR7lKKKfTwCYvWA tools/examples/xc_dom_control.py
401d7e16RJj-lbtsVEjua6HYAIiKiA tools/examples/xc_dom_create.py
-40c9c468pXANclL7slGaoD0kSrIwoQ tools/examples/xm_dom_create.py
40cf2937oKlROYOJTN8GWwWM5AmjBg tools/examples/xmdefaults
40dfd40auJwNnb8NoiSnRkvZaaXkUg tools/examples/xmnetbsd
-40e033325Sjqs-_4TuzeUEprP_gYFg tools/lib/allocate.c
-40e03332KYz7o1bn2MG_KPbBlyoIMA tools/lib/allocate.h
-40e03332IyRttYoXKoJla5qCC514SQ tools/lib/debug.h
-40e03332qV5tJ-GJZjo-LBCeGuEjJA tools/lib/enum.c
-40e03332wwMVxfobgA1PSMTSAGLiCw tools/lib/enum.h
-40e03332p5Dc_owJQRuN72ymJZddFQ tools/lib/file_stream.c
-40e03332jWfB2viAhLSkq1WK0r_iDQ tools/lib/file_stream.h
-40e03332rUjNMGg11n2rN6V4DCrvOg tools/lib/gzip_stream.c
-40e033321O5Qg22haLoq5lpmk4tooQ tools/lib/gzip_stream.h
-40e03332QrTR96tc6yS2rMBpd2mq1A tools/lib/hash_table.c
-40e033325KoIb0d_uy8s7b5DUR9fPQ tools/lib/hash_table.h
-40e03332ihnBGzHykVwZnFmkAppb4g tools/lib/iostream.c
-40e03332UGwbLR4wsw4ft14p0Yw5pg tools/lib/iostream.h
-40e0333245DLDzJemeSVBLuutHtzEQ tools/lib/kernel_stream.c
-40e03332aK0GkgpDdc-PVTkWKTeOBg tools/lib/kernel_stream.h
-40e03332HJ0cDcZDKDUUT-tEiBWOZw tools/lib/lexis.c
-40e03332tnH9Ggzxbfi3xY9Vh2hUlg tools/lib/lexis.h
-40e03332aYIW0BNBh6wXuKKn_P7Yyg tools/lib/lzi_stream.c
-40e0333233voTffE4cJSMGJARfiSSQ tools/lib/lzi_stream.h
-40e03332FXuMoUnfsAKSgV8X4rFbYQ tools/lib/lzo_stream.c
-40e03332InJaiLfpDcIXBy2fI0RFGQ tools/lib/lzo_stream.h
-40e03332a5SCuRsejHStTuWzMQNv8Q tools/lib/marshal.c
-40e03332TwKyJrZQiiQfNq4vc2hpgw tools/lib/marshal.h
-40e033328ccHlJuTR1FswYL_EC6LFA tools/lib/socket_stream.c
-40e03332P0KVQGkmahj47aafo1X0nA tools/lib/socket_stream.h
-40e03332KT_tnnoAMbPVAZBB7kSOAQ tools/lib/string_stream.c
-40e03332-VtK6_OZa1vMHXFil8uq6w tools/lib/string_stream.h
-40e03332dDtczi6YX7_mMxhYjJeAdQ tools/lib/sxpr.c
-40e03332QPuyNKDOTIYVvkwK5qO-vg tools/lib/sxpr.h
-40e03332Pi0_osJ3XPBi38ADPqdl4A tools/lib/sxpr_parser.c
-40e033324v5QFMvWEXXzv38uUT9kHg tools/lib/sxpr_parser.h
-40e03332gKUInsqtxQOV4mPiMqf_dg tools/lib/sys_ctype.h
-40e03332Rkvq6nn_UNjzAAK_Tk9v1g tools/lib/sys_net.c
-40e03332lQHvQHw4Rh7VsT1_sui29A tools/lib/sys_net.h
-40e033321smklZd7bDSdWvQCeIshtg tools/lib/sys_string.c
-40e03332h5V611rRWURRLqb1Ekatxg tools/lib/sys_string.h
-40e03332u4q5kgF0N7RfqB4s0pZVew tools/lib/xdr.c
-40e03332hY16nfRXF4gGd5S1aUJUBw tools/lib/xdr.h
+3fbba6dbDfYvJSsw9500b4SZyUhxjQ tools/libxc/Makefile
+3fbba6dc1uU7U3IFeF6A-XEOYF2MkQ tools/libxc/rpm.spec
+3fbba6dcrNxtygEcgJYAJJ1gCQqfsA tools/libxc/xc.h
+40589968oCfoUlXd460CjVAkBE8IBA tools/libxc/xc_atropos.c
+3fbba6dbEVkVMX0JuDFzap9jeaucGA tools/libxc/xc_bvtsched.c
+3fbba6dbasJQV-MVElDC0DGSHMiL5w tools/libxc/xc_domain.c
+40278d99BLsfUv3qxv0I8C1sClZ0ow tools/libxc/xc_elf.h
+403e0977Bjsm_e82pwvl9VvaJxh8Gg tools/libxc/xc_evtchn.c
+40e03333Eegw8czSWvHsbKxrRZJjRA tools/libxc/xc_io.c
+40e03333vrWGbLAhyJjXlqCHaJt7eA tools/libxc/xc_io.h
+3fbba6dbNCU7U6nsMYiXzKkp3ztaJg tools/libxc/xc_linux_build.c
+3fbba6dbl267zZOAVHYLOdLCdhcZMw tools/libxc/xc_linux_restore.c
+3fbba6db7li3FJiABYtCmuGxOJxEGw tools/libxc/xc_linux_save.c
+3fbba6db7WnnJr0KFrIFrqNlSKvFYg tools/libxc/xc_misc.c
+40278d9ctaHVDaEuwhXI3Om2JOjx9w tools/libxc/xc_netbsd_build.c
+4051bce6CHAsYh8P5t2OHDtRWOP9og tools/libxc/xc_physdev.c
+3fbba6dctWRWlFJkYb6hdix2X4WMuw tools/libxc/xc_private.c
+3fbba6dcbVrG2hPzEzwdeV_UC8kydQ tools/libxc/xc_private.h
+40589968UQFnJeOMn8UIFLbXBuwXjw tools/libxc/xc_rrobin.c
+40e1b09dMYB4ItGCqcMIzirdMd9I-w tools/libxutil/Makefile
+40e033325Sjqs-_4TuzeUEprP_gYFg tools/libxutil/allocate.c
+40e03332KYz7o1bn2MG_KPbBlyoIMA tools/libxutil/allocate.h
+40e03332IyRttYoXKoJla5qCC514SQ tools/libxutil/debug.h
+40e03332qV5tJ-GJZjo-LBCeGuEjJA tools/libxutil/enum.c
+40e03332wwMVxfobgA1PSMTSAGLiCw tools/libxutil/enum.h
+40e03332p5Dc_owJQRuN72ymJZddFQ tools/libxutil/file_stream.c
+40e03332jWfB2viAhLSkq1WK0r_iDQ tools/libxutil/file_stream.h
+40e03332rUjNMGg11n2rN6V4DCrvOg tools/libxutil/gzip_stream.c
+40e033321O5Qg22haLoq5lpmk4tooQ tools/libxutil/gzip_stream.h
+40e03332QrTR96tc6yS2rMBpd2mq1A tools/libxutil/hash_table.c
+40e033325KoIb0d_uy8s7b5DUR9fPQ tools/libxutil/hash_table.h
+40e03332ihnBGzHykVwZnFmkAppb4g tools/libxutil/iostream.c
+40e03332UGwbLR4wsw4ft14p0Yw5pg tools/libxutil/iostream.h
+40e0333245DLDzJemeSVBLuutHtzEQ tools/libxutil/kernel_stream.c
+40e03332aK0GkgpDdc-PVTkWKTeOBg tools/libxutil/kernel_stream.h
+40e03332HJ0cDcZDKDUUT-tEiBWOZw tools/libxutil/lexis.c
+40e03332tnH9Ggzxbfi3xY9Vh2hUlg tools/libxutil/lexis.h
+40e03332aYIW0BNBh6wXuKKn_P7Yyg tools/libxutil/lzi_stream.c
+40e0333233voTffE4cJSMGJARfiSSQ tools/libxutil/lzi_stream.h
+40e03332FXuMoUnfsAKSgV8X4rFbYQ tools/libxutil/lzo_stream.c
+40e03332InJaiLfpDcIXBy2fI0RFGQ tools/libxutil/lzo_stream.h
+40e03332a5SCuRsejHStTuWzMQNv8Q tools/libxutil/marshal.c
+40e03332TwKyJrZQiiQfNq4vc2hpgw tools/libxutil/marshal.h
+40e033328ccHlJuTR1FswYL_EC6LFA tools/libxutil/socket_stream.c
+40e03332P0KVQGkmahj47aafo1X0nA tools/libxutil/socket_stream.h
+40e03332KT_tnnoAMbPVAZBB7kSOAQ tools/libxutil/string_stream.c
+40e03332-VtK6_OZa1vMHXFil8uq6w tools/libxutil/string_stream.h
+40e03332dDtczi6YX7_mMxhYjJeAdQ tools/libxutil/sxpr.c
+40e03332QPuyNKDOTIYVvkwK5qO-vg tools/libxutil/sxpr.h
+40e03332Pi0_osJ3XPBi38ADPqdl4A tools/libxutil/sxpr_parser.c
+40e033324v5QFMvWEXXzv38uUT9kHg tools/libxutil/sxpr_parser.h
+40e03332gKUInsqtxQOV4mPiMqf_dg tools/libxutil/sys_ctype.h
+40e03332Rkvq6nn_UNjzAAK_Tk9v1g tools/libxutil/sys_net.c
+40e03332lQHvQHw4Rh7VsT1_sui29A tools/libxutil/sys_net.h
+40e033321smklZd7bDSdWvQCeIshtg tools/libxutil/sys_string.c
+40e03332h5V611rRWURRLqb1Ekatxg tools/libxutil/sys_string.h
+40e03332u4q5kgF0N7RfqB4s0pZVew tools/libxutil/xdr.c
+40e03332hY16nfRXF4gGd5S1aUJUBw tools/libxutil/xdr.h
3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile
40ab2cfawIw8tsYo0dQKtp83h4qfTQ tools/misc/fakei386xen
3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile
3f5ef5a2dTZP0nnsFoeq2jRf3mWDDg tools/misc/xen-clone.README
3f870808zS6T6iFhqYPGelroZlVfGQ tools/misc/xen_cpuperf.c
405eedf6_nnNhFQ1I85lhCkLK6jFGA tools/misc/xencons
+40c9c4697z76HDfkCLdMhmaEwzFoNQ tools/misc/xend
4056f5155QYZdsk-1fLdjsZPFTnlhg tools/misc/xensymoops.py
-3fbca441SjQr8vJwTQIgH1laysaWog tools/xc/Makefile
-3fbba6dbDfYvJSsw9500b4SZyUhxjQ tools/xc/lib/Makefile
-3fbba6dc1uU7U3IFeF6A-XEOYF2MkQ tools/xc/lib/rpm.spec
-3fbba6dcrNxtygEcgJYAJJ1gCQqfsA tools/xc/lib/xc.h
-40589968oCfoUlXd460CjVAkBE8IBA tools/xc/lib/xc_atropos.c
-3fbba6dbEVkVMX0JuDFzap9jeaucGA tools/xc/lib/xc_bvtsched.c
-3fbba6dbasJQV-MVElDC0DGSHMiL5w tools/xc/lib/xc_domain.c
-40278d99BLsfUv3qxv0I8C1sClZ0ow tools/xc/lib/xc_elf.h
-403e0977Bjsm_e82pwvl9VvaJxh8Gg tools/xc/lib/xc_evtchn.c
-40e03333Eegw8czSWvHsbKxrRZJjRA tools/xc/lib/xc_io.c
-40e03333vrWGbLAhyJjXlqCHaJt7eA tools/xc/lib/xc_io.h
-3fbba6dbNCU7U6nsMYiXzKkp3ztaJg tools/xc/lib/xc_linux_build.c
-3fbba6dbl267zZOAVHYLOdLCdhcZMw tools/xc/lib/xc_linux_restore.c
-3fbba6db7li3FJiABYtCmuGxOJxEGw tools/xc/lib/xc_linux_save.c
-3fbba6db7WnnJr0KFrIFrqNlSKvFYg tools/xc/lib/xc_misc.c
-40278d9ctaHVDaEuwhXI3Om2JOjx9w tools/xc/lib/xc_netbsd_build.c
-4051bce6CHAsYh8P5t2OHDtRWOP9og tools/xc/lib/xc_physdev.c
-3fbba6dctWRWlFJkYb6hdix2X4WMuw tools/xc/lib/xc_private.c
-3fbba6dcbVrG2hPzEzwdeV_UC8kydQ tools/xc/lib/xc_private.h
-40589968UQFnJeOMn8UIFLbXBuwXjw tools/xc/lib/xc_rrobin.c
-3fbd0a3dTwnDcfdw0-v46dPbX98zDw tools/xc/py/Makefile
-3fbd0a42l40lM0IICw2jXbQBVZSdZg tools/xc/py/Xc.c
-3fbd0a40yT6G3M9hMpaz5xTUdl0E4g tools/xc/py/setup.py
-40c9c468icGyC5RAF1bRKsCXPDCvsA tools/xen/Makefile
-40dc4076hGpwa8-sWRN0jtXZeQJuKg tools/xen/lib/__init__.py
-40dfd40aMOhnw_cQLve9462UR5yYxQ tools/xen/lib/ext/__init__.py
-40d8915cyoVA0hJxiBFNymL7YvDaRg tools/xen/lib/util/Brctl.py
-40dfd40aGqGkiopOOgJxSF4iCbHM0Q tools/xen/lib/util/__init__.py
-4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/xen/lib/util/console_client.py
-40c9c468IienauFHQ_xJIcqnPJ8giQ tools/xen/lib/util/ip.py
-4059c6a0pnxhG8hwSOivXybbGOwuXw tools/xen/lib/util/tempfile.py
-40c9c468SNuObE_YWARyS0hzTPSzKg tools/xen/lib/xend/Args.py
-40c9c468Um_qc66OQeLEceIz1pgD5g tools/xen/lib/xend/EventServer.py
-40c9c468U8EVl0d3G--8YXVg6VJD3g tools/xen/lib/xend/EventTypes.py
-40c9c468QJTEuk9g4qHxGpmIi70PEQ tools/xen/lib/xend/PrettyPrint.py
-40e15b7eeQxWE_hUPB2YTgM9fsZ1PQ tools/xen/lib/xend/Vifctl.py
-40c9c4688m3eqnC8fhLu1APm36VOVA tools/xen/lib/xend/XendClient.py
-40c9c468t6iIKTjwuYoe-UMCikDcOQ tools/xen/lib/xend/XendConsole.py
-40c9c468WnXs6eOUSff23IIGI4kMfQ tools/xen/lib/xend/XendDB.py
-40c9c468fSl3H3IypyT0ppkbb0ZT9A tools/xen/lib/xend/XendDomain.py
-40c9c468bbKq3uC7_fuNUkiMMjArdw tools/xen/lib/xend/XendDomainConfig.py
-40c9c4685ykq87_n1kVUbMr9flx9fg tools/xen/lib/xend/XendDomainInfo.py
-40c9c46854nsHmuxHQHncKk5rAs5NA tools/xen/lib/xend/XendMigrate.py
-40c9c468M96gA1EYDvNa5w5kQNYLFA tools/xen/lib/xend/XendNode.py
-40c9c4686jruMyZIqiaZRMiMoqMJtg tools/xen/lib/xend/XendRoot.py
-40c9c468xzANp6o2D_MeCYwNmOIUsQ tools/xen/lib/xend/XendVnet.py
-40c9c468x191zetrVlMnExfsQWHxIQ tools/xen/lib/xend/__init__.py
-40c9c468S2YnCEKmk4ey8XQIST7INg tools/xen/lib/xend/encode.py
-40c9c468DCpMe542varOolW1Xc68ew tools/xen/lib/xend/server/SrvBase.py
-40c9c468IxQabrKJSWs0aEjl-27mRQ tools/xen/lib/xend/server/SrvConsole.py
-40c9c4689Io5bxfbYIfRiUvsiLX0EQ tools/xen/lib/xend/server/SrvConsoleDir.py
-40c9c468woSmBByfeXA4o_jGf2gCgA tools/xen/lib/xend/server/SrvDaemon.py
-40c9c468kACsmkqjxBWKHRo071L26w tools/xen/lib/xend/server/SrvDeviceDir.py
-40c9c468EQZJVkCLds-OhesJVVyZbQ tools/xen/lib/xend/server/SrvDir.py
-40c9c468TyHZUq8sk0FF_vxM6Sozrg tools/xen/lib/xend/server/SrvDomain.py
-40c9c469WzajDjutou3X7FmL9hMf3g tools/xen/lib/xend/server/SrvDomainDir.py
-40c9c469-8mYEJJTAR6w_ClrJRAfwQ tools/xen/lib/xend/server/SrvEventDir.py
-40c9c4694eu5759Dehr4Uhakei0EMg tools/xen/lib/xend/server/SrvNode.py
-40c9c469TaZ83ypsrktmPSHLEZiP5w tools/xen/lib/xend/server/SrvRoot.py
-40c9c469W3sgDMbBJYQdz5wbQweL0Q tools/xen/lib/xend/server/SrvServer.py
-40c9c469aq7oXrE1Ngqf3_lBqL0RoQ tools/xen/lib/xend/server/SrvVnetDir.py
-40c9c469Y_aimoOFfUZoS-4eV8gEKg tools/xen/lib/xend/server/__init__.py
-40c9c4692hckPol_EK0EGB16ZyDsyQ tools/xen/lib/xend/server/blkif.py
-40c9c469N2-b3GqpLHHHPZykJPLVvA tools/xen/lib/xend/server/channel.py
-40c9c469hJ_IlatRne-9QEa0-wlquw tools/xen/lib/xend/server/console.py
-40c9c469UcNJh_NuLU0ytorM0Lk5Ow tools/xen/lib/xend/server/controller.py
-40c9c469vHh-qLiiubdbKEQbJf18Zw tools/xen/lib/xend/server/cstruct.py
-40d83983OXjt-y3HjSCcuoPp9rzvmw tools/xen/lib/xend/server/domain.py
-40c9c469yrm31i60pGKslTi2Zgpotg tools/xen/lib/xend/server/messages.py
-40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/xen/lib/xend/server/netif.py
-40c9c469ZqILEQ8x6yWy0_51jopiCg tools/xen/lib/xend/server/params.py
-40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/xen/lib/xend/sxp.py
-40d05079aFRp6NQdo5wIh5Ly31c0cg tools/xen/lib/xm/__init__.py
-40cf2937gKQcATgXKGtNeWb1PDH5nA tools/xen/lib/xm/create.py
-40cf2937isyS250zyd0Q2GuEDoNXfQ tools/xen/lib/xm/main.py
-40cf2937PSslwBliN1g7ofDy2H_RhA tools/xen/lib/xm/opts.py
-40cf2937Z8WCNOnO2FcWdubvEAF9QQ tools/xen/lib/xm/shutdown.py
-40c9c469n2RRwCmjWdjdyyVRWKmgWg tools/xen/setup.py
-40e15b7edWEtBf_oe3eBwGKuh1dyzQ tools/xen/vifctl
-40c9c4697z76HDfkCLdMhmaEwzFoNQ tools/xen/xend
-40cf2937dqM1jWW87O5OoOYND8leuA tools/xen/xm
+40cf2937dqM1jWW87O5OoOYND8leuA tools/misc/xm
+40c9c468icGyC5RAF1bRKsCXPDCvsA tools/python/Makefile
+40c9c469n2RRwCmjWdjdyyVRWKmgWg tools/python/setup.py
+40dc4076hGpwa8-sWRN0jtXZeQJuKg tools/python/xen/__init__.py
+40dfd40aMOhnw_cQLve9462UR5yYxQ tools/python/xen/ext/__init__.py
+3fbd0a3dTwnDcfdw0-v46dPbX98zDw tools/python/xen/ext/xc/Makefile
+3fbd0a40yT6G3M9hMpaz5xTUdl0E4g tools/python/xen/ext/xc/setup.py
+3fbd0a42l40lM0IICw2jXbQBVZSdZg tools/python/xen/ext/xc/xc.c
+40dc4076St6AmPTmQPrtQ6LGHPxGmw tools/python/xen/ext/xu/__init__.py
+40dc4076pVeE1kEEWzcUaNZin65kCA tools/python/xen/ext/xu/domain_controller.h
+40dc4076CwBYRTUQDdbdU1L6KcLgSw tools/python/xen/ext/xu/xu.c
+40d8915cyoVA0hJxiBFNymL7YvDaRg tools/python/xen/util/Brctl.py
+40dfd40aGqGkiopOOgJxSF4iCbHM0Q tools/python/xen/util/__init__.py
+4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/python/xen/util/console_client.py
+40c9c468IienauFHQ_xJIcqnPJ8giQ tools/python/xen/util/ip.py
+4059c6a0pnxhG8hwSOivXybbGOwuXw tools/python/xen/util/tempfile.py
+40c9c468SNuObE_YWARyS0hzTPSzKg tools/python/xen/xend/Args.py
+40c9c468Um_qc66OQeLEceIz1pgD5g tools/python/xen/xend/EventServer.py
+40c9c468U8EVl0d3G--8YXVg6VJD3g tools/python/xen/xend/EventTypes.py
+40c9c468QJTEuk9g4qHxGpmIi70PEQ tools/python/xen/xend/PrettyPrint.py
+40e15b7eeQxWE_hUPB2YTgM9fsZ1PQ tools/python/xen/xend/Vifctl.py
+40c9c4688m3eqnC8fhLu1APm36VOVA tools/python/xen/xend/XendClient.py
+40c9c468t6iIKTjwuYoe-UMCikDcOQ tools/python/xen/xend/XendConsole.py
+40c9c468WnXs6eOUSff23IIGI4kMfQ tools/python/xen/xend/XendDB.py
+40c9c468fSl3H3IypyT0ppkbb0ZT9A tools/python/xen/xend/XendDomain.py
+40c9c468bbKq3uC7_fuNUkiMMjArdw tools/python/xen/xend/XendDomainConfig.py
+40c9c4685ykq87_n1kVUbMr9flx9fg tools/python/xen/xend/XendDomainInfo.py
+40c9c46854nsHmuxHQHncKk5rAs5NA tools/python/xen/xend/XendMigrate.py
+40c9c468M96gA1EYDvNa5w5kQNYLFA tools/python/xen/xend/XendNode.py
+40c9c4686jruMyZIqiaZRMiMoqMJtg tools/python/xen/xend/XendRoot.py
+40c9c468xzANp6o2D_MeCYwNmOIUsQ tools/python/xen/xend/XendVnet.py
+40c9c468x191zetrVlMnExfsQWHxIQ tools/python/xen/xend/__init__.py
+40c9c468S2YnCEKmk4ey8XQIST7INg tools/python/xen/xend/encode.py
+40c9c468DCpMe542varOolW1Xc68ew tools/python/xen/xend/server/SrvBase.py
+40c9c468IxQabrKJSWs0aEjl-27mRQ tools/python/xen/xend/server/SrvConsole.py
+40c9c4689Io5bxfbYIfRiUvsiLX0EQ tools/python/xen/xend/server/SrvConsoleDir.py
+40c9c468woSmBByfeXA4o_jGf2gCgA tools/python/xen/xend/server/SrvDaemon.py
+40c9c468kACsmkqjxBWKHRo071L26w tools/python/xen/xend/server/SrvDeviceDir.py
+40c9c468EQZJVkCLds-OhesJVVyZbQ tools/python/xen/xend/server/SrvDir.py
+40c9c468TyHZUq8sk0FF_vxM6Sozrg tools/python/xen/xend/server/SrvDomain.py
+40c9c469WzajDjutou3X7FmL9hMf3g tools/python/xen/xend/server/SrvDomainDir.py
+40c9c469-8mYEJJTAR6w_ClrJRAfwQ tools/python/xen/xend/server/SrvEventDir.py
+40c9c4694eu5759Dehr4Uhakei0EMg tools/python/xen/xend/server/SrvNode.py
+40c9c469TaZ83ypsrktmPSHLEZiP5w tools/python/xen/xend/server/SrvRoot.py
+40c9c469W3sgDMbBJYQdz5wbQweL0Q tools/python/xen/xend/server/SrvServer.py
+40c9c469aq7oXrE1Ngqf3_lBqL0RoQ tools/python/xen/xend/server/SrvVnetDir.py
+40c9c469Y_aimoOFfUZoS-4eV8gEKg tools/python/xen/xend/server/__init__.py
+40c9c4692hckPol_EK0EGB16ZyDsyQ tools/python/xen/xend/server/blkif.py
+40c9c469N2-b3GqpLHHHPZykJPLVvA tools/python/xen/xend/server/channel.py
+40c9c469hJ_IlatRne-9QEa0-wlquw tools/python/xen/xend/server/console.py
+40c9c469UcNJh_NuLU0ytorM0Lk5Ow tools/python/xen/xend/server/controller.py
+40c9c469vHh-qLiiubdbKEQbJf18Zw tools/python/xen/xend/server/cstruct.py
+40d83983OXjt-y3HjSCcuoPp9rzvmw tools/python/xen/xend/server/domain.py
+40c9c469yrm31i60pGKslTi2Zgpotg tools/python/xen/xend/server/messages.py
+40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/python/xen/xend/server/netif.py
+40c9c469ZqILEQ8x6yWy0_51jopiCg tools/python/xen/xend/server/params.py
+40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py
+40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py
+40cf2937gKQcATgXKGtNeWb1PDH5nA tools/python/xen/xm/create.py
+40cf2937isyS250zyd0Q2GuEDoNXfQ tools/python/xen/xm/main.py
+40cf2937PSslwBliN1g7ofDy2H_RhA tools/python/xen/xm/opts.py
+40cf2937Z8WCNOnO2FcWdubvEAF9QQ tools/python/xen/xm/shutdown.py
403a3edbrr8RE34gkbR40zep98SXbg tools/xentrace/Makefile
40a107afN60pFdURgBv9KwEzgRl5mQ tools/xentrace/formats
4050c413PhhLNAYk3TEwP37i_iLw9Q tools/xentrace/xentrace.8
403a3edbVpV2E_wq1zeEkJ_n4Uu2eg tools/xentrace/xentrace.c
403a3edblCUrzSj0mmKhO5HOPrOrSQ tools/xentrace/xentrace_format
4050c413NtuyIq5lsYJV4P7KIjujXw tools/xentrace/xentrace_format.1
-40dfd40a0QtsSGigB9TCpVGWZmhlNA tools/xu/Makefile
-40dc4076St6AmPTmQPrtQ6LGHPxGmw tools/xu/lib/__init__.py
-40dc4076pVeE1kEEWzcUaNZin65kCA tools/xu/lib/domain_controller.h
-40dc4076CwBYRTUQDdbdU1L6KcLgSw tools/xu/lib/xu.c
-40dc4076FyWUYS2nX9YufgglUzKX2A tools/xu/setup.py
3f72f1bdJPsV3JCnBqs9ddL9tr6D2g xen/COPYING
3ddb79bcbOVHh38VJzc97-JEGD4dJQ xen/Makefile
3ddb79bcWnTwYsQRWl_PaneJfa6p0w xen/Rules.mk
xen/xen-syms
xen/xen.*
tools/xc/lib/.xc_rrobin.o.d
+tools/libxc/.xc_atropos.o.d
+tools/libxc/.xc_bvtsched.o.d
+tools/libxc/.xc_domain.o.d
+tools/libxc/.xc_evtchn.o.d
+tools/libxc/.xc_io.o.d
+tools/libxc/.xc_linux_build.o.d
+tools/libxc/.xc_linux_restore.o.d
+tools/libxc/.xc_linux_save.o.d
+tools/libxc/.xc_misc.o.d
+tools/libxc/.xc_netbsd_build.o.d
+tools/libxc/.xc_physdev.o.d
+tools/libxc/.xc_private.o.d
+tools/libxc/.xc_rrobin.o.d
+tools/libxutil/.allocate.o.d
+tools/libxutil/.file_stream.o.d
+tools/libxutil/.gzip_stream.o.d
+tools/libxutil/.iostream.o.d
+tools/libxutil/.sys_net.o.d
+tools/libxutil/.sys_string.o.d
--- /dev/null
+# -*- mode: Makefile; -*-
+XEN_HYPERVISOR_IFS = $(XEN_ROOT)/xen/include/hypervisor-ifs
+XEN_LINUX_INCLUDE = $(XEN_ROOT)/linux-xen-sparse/include
+XEN_XU = $(XEN_ROOT)/tools/python/xen/ext/xu
+XEN_XC = $(XEN_ROOT)/tools/python/xen/ext/xc
+XEN_LIBXC = $(XEN_ROOT)/tools/libxc
+XEN_LIBXUTIL = $(XEN_ROOT)/tools/libxutil
all:
- $(MAKE) -C xc
- $(MAKE) -C xu
+ $(MAKE) -C libxutil
+ $(MAKE) -C libxc
$(MAKE) -C misc
$(MAKE) -C examples
$(MAKE) -C xentrace
- $(MAKE) -C xen
+ $(MAKE) -C python
install: all
- $(MAKE) -C xc install
- $(MAKE) -C xu install
+ $(MAKE) -C libxutil install
+ $(MAKE) -C libxc install
$(MAKE) -C misc install
$(MAKE) -C examples install
$(MAKE) -C xentrace install
- $(MAKE) -C xen install
+ $(MAKE) -C python install
dist: $(TARGET)
$(MAKE) prefix=`pwd`/../../install dist=yes install
clean:
- $(MAKE) -C xc clean
- $(MAKE) -C xu clean
+ $(MAKE) -C libxutil clean
+ $(MAKE) -C libxc clean
$(MAKE) -C misc clean
$(MAKE) -C examples clean
$(MAKE) -C xentrace clean
- $(MAKE) -C xen clean
+ $(MAKE) -C python clean
INSTALL = $(wildcard *.py)
+
ETC = defaults democd netbsd xmdefaults
ETCDIR = /etc/xen
+
INITD = init.d/xendomains init.d/xend
+XEND = vifctl
+XEND_DIR = $(ETCDIR)/xend
+
all:
-install: all
+install: all install-bin install-initd install-etc install-xend
+
+install-bin:
mkdir -p $(prefix)/usr/bin
+ install -m0755 $(INSTALL) $(prefix)/usr/bin
+
+install-initd:
+ mkdir -p $(prefix)/etc/init.d
+ install -m0755 $(INITD) $(prefix)/etc/init.d
+
+install-etc:
mkdir -p $(prefix)$(ETCDIR)
mkdir -p $(prefix)$(ETCDIR)/auto
- mkdir -p $(prefix)/etc/init.d
- install -m0755 $(INSTALL) $(prefix)/usr/bin
for i in $(ETC); \
do [ -a $(prefix)/$(ETCDIR)/$$i ] || \
install -m0644 $$i $(prefix)$(ETCDIR); \
done
- install -m0755 $(INITD) $(prefix)/etc/init.d
+
+install-xend:
+ mkdir -p $(prefix)$(XEND_DIR)
+ for i in $(XEND); \
+ do [ -a $(prefix)/$(XEND_DIR)/$$i ] || \
+ install -m0755 $$i $(prefix)$(XEND_DIR); \
+ done
+
clean:
--- /dev/null
+#!/usr/bin/python
+# -*- mode: python; -*-
+#============================================================================
+# Xen vif control script. Lives in /etc/xen/xend.
+#
+# vifctl init [bridge=<bridge>] [interface=<interface>]
+#
+# Called when xend starts up. Default behaviour is to create <bridge>
+# and add <interface> to it, moving its IP address to <bridge> and adjusting routes.
+#
+# vifctl (up|down) vif=<vif> mac=<mac> [bridge=<bridge>] (ipaddr=<ipaddr>)*
+#
+# Called when a vif is brought up or down. Default behaviour is to add
+# the vif to <bridge> on up and remove it from the bridge on down.
+# If ipaddr is specified, iptables rules for the ip addresses are
+# added on up and removed on down. The bridge a vif is added to can
+# be set in the vm config.
+#
+# The default bridge is nbe-br.
+# The default interface is eth0.
+#
+#============================================================================
+
+import sys
+import types
+
+from xen.util import Brctl
+
+from xen.xend import XendRoot
+xroot = XendRoot.instance()
+
+class VifControl:
+
+ prefix = 'vifctl_'
+
+ DEFAULT_BRIDGE = 'nbe-br'
+ DEFAULT_INTERFACE = 'eth0'
+
+ def __init__(self):
+ self.name = 'vifctl'
+
+ def main(self, args):
+ #print self.name, args
+ if len(args) < 2:
+ usage(args)
+ self.name = args[0]
+ cmd = self.prefix + args[1]
+ meth = getattr(self, cmd, self.unknown)
+ meth(args[1:])
+
+ def usage(self, args, out=sys.stderr):
+ print >>out, 'Missing command, try \n%s help' % self.name
+
+ def unknown(self, args, out=sys.stderr):
+ print >>out, 'Unknown command:', args[1]
+ self.help(out=out)
+ sys.exit(1)
+
+ def help(self, out=sys.stdout):
+ print >>out, 'Commands are:',
+ for x in vars(self):
+ if x.startswith(prefix):
+ cmd = x[len(prefix):]
+ print >>out, cmd,
+ print >>out
+
+ def getparams(self, d, args, req=[]):
+ """Parse args of the form 'key=val'. Valid keys are the ones
+ in the dict 'd' passed in. If entries in 'd' have list values the
+ values of the keys are appended.
+
+ If 'req' is specified it is a list of required keys.
+ """
+ for x in args:
+ (k, v) = x.split('=')
+ k = k.strip()
+ v = v.strip()
+ if k not in d:
+ print >>sys.stderr, 'Invalid parameter: ', k
+ sys.exit(1)
+ vold = d[k]
+ if isinstance(vold , types.ListType):
+ d[k] = vold + v
+ else:
+ d[k] = v
+ for x in req:
+ if not d[x]:
+ print >>sys.stderr, 'Missing parameter:', x
+ sys.exit(1)
+ return d
+
+ def vifctl_help(self, args):
+ self.help()
+
+ def default_bridge(self):
+ return xroot.get_config_value('bridge', self.DEFAULT_BRIDGE)
+
+ def default_interface(self):
+ return xroot.get_config_value('interface', self.DEFAULT_INTERFACE)
+
+ def vifctl_init(self, args):
+ """Entry point for 'vifctl init'.
+ """
+ d = { 'bridge' : self.default_bridge(),
+ 'interface': self.default_interface() }
+ params = self.getparams(d, args[1:])
+ interface = params['interface']
+ bridge = params['bridge']
+ # Create bridge 'bridge'.
+ Brctl.bridge_create(bridge)
+ # Reconfigure so that 'interface' is added to 'bridge',
+ # and 'bridge' has the IP address from 'interface'.
+ Brctl.reconfigure(interface, bridge)
+
+ def vifparams(self, args):
+ d = { 'vif' : None,
+ 'mac' : None,
+ 'bridge': self.default_bridge(),
+ 'ipaddr': [] }
+ d = self.getparams(d, args, req=['vif', 'mac'])
+ return d
+
+ def vifctl_up(self, args):
+ """Entry point for 'vifctl up'.
+ """
+ params = self.vifparams(args[1:])
+ # Add the vif to its bridge.
+ Brctl.vif_bridge_add(params)
+ if params['ipaddr']:
+ # Add iptables rules for the ip addresses.
+ vif = params['vif']
+ for ipaddr in params['ipaddr']:
+ Brctl.vif_restrict_addr(vif, ipaddr)
+
+ def vifctl_down(self, args):
+ """Entry point for 'vifctl down'.
+ """
+ params = self.vifparams(args[1:])
+ # Remove the vif from its bridge.
+ Brctl.vif_bridge_rem(params)
+ if params['ip']:
+ # Remove iptables rules for the ip addresses.
+ vif = params['vif']
+ for ip in params['ip']:
+ Brctl.vif_restrict_addr(vif, ip, delete=1)
+
+
+if __name__ == "__main__":
+ VifControl().main(sys.argv)
+++ /dev/null
-#!/usr/bin/env python
-
-import string
-import sys
-import os
-import os.path
-import time
-import socket
-import getopt
-import signal
-import syslog
-import xenctl.ip
-import xenctl.utils
-import xenctl.console_client
-
-from xenmgr import sxp
-from xenmgr import PrettyPrint
-from xenmgr.XendClient import server
-
-config_dir = '/etc/xc/'
-config_file = xc_config_file = config_dir + 'defaults'
-
-def main_usage ():
- print >>sys.stderr,"""
-Usage: %s <args>
-
-This tool is used to create and start new domains. It reads defaults
-from a file written in Python, having allowed variables to be set and
-passed into the file. Further command line arguments allow the
-defaults to be overridden. The defaults for each parameter are listed
-in [] brackets. Arguments are as follows:
-
-Arguments to control the parsing of the defaults file:
- -f config_file -- Use the specified defaults script.
- Default: ['%s']
- -L state_file -- Load virtual machine memory state from state_file
- -D foo=bar -- Set variable foo=bar before parsing config
- E.g. '-D vmid=3;ip=1.2.3.4'
- -h -- Print extended help message, including all arguments
- -n -- Dry run only, don't actually create domain
- Prints the config, suitable for -F.
- -q -- Quiet - write output only to the system log
- -F domain_config -- Build domain using the config in the file.
- Suitable files can be made using '-n' to output a config.
-""" % (sys.argv[0], xc_config_file)
-
-def extra_usage ():
- print >>sys.stderr,"""
-Arguments to override current config read from '%s':
- -c -- Turn into console terminal after domain is created
- -k image -- Path to kernel image ['%s']
- -r ramdisk -- Path to ramdisk (or empty) ['%s']
- -b builder_fn -- Function to use to build domain ['%s']
- -m mem_size -- Initial memory allocation in MB [%dMB]
- -N domain_name -- Set textual name of domain ['%s']
- -a auto_restart -- Restart domain on exit, yes/no ['%d']
- -e vbd_expert -- Safety catch to avoid some disk accidents ['%s']
- -d udisk,dev,rw -- Add disk, partition, or virtual disk to domain. E.g. to
- make partion sda4 available to the domain as hda1 with
- read-write access: '-d phy:sda4,hda1,rw' To add
- multiple disks use multiple -d flags or seperate with ';'
- Default: ['%s']
- -i vfr_ipaddr -- Add IP address to the list which Xen will route to
- the domain. Use multiple times to add more IP addrs.
- Default: ['%s']
-
-Args to override the kernel command line, which is concatenated from these:
- -I cmdline_ip -- Override 'ip=ipaddr:nfsserv:gateway:netmask::eth0:off'
- Default: ['%s']
- -R cmdline_root -- Override root device parameters.
- Default: ['%s']
- -E cmdline_extra -- Override extra kernel args and rc script env vars.
- Default: ['%s']
-
-""" % (config_file,
- image, ramdisk, builder_fn, mem_size, domain_name, auto_restart,
- vbd_expert,
- printvbds( vbd_list ),
- reduce ( (lambda a,b: a+':'+b), vfr_ipaddr,'' )[1:],
- cmdline_ip, cmdline_root, cmdline_extra)
-
-def config_usage (): pass
-
-def answer ( s ):
- s = string.lower(s)
- if s == 'yes' or s == 'true' or s == '1': return 1
- return 0
-
-def printvbds ( v ):
- s=''
- for (a,b,c) in v:
- s = s + '; %s,%s,%s' % (a,b,c)
- return s[2:]
-
-def output(string):
- global quiet
- syslog.syslog(string)
- if not quiet:
- print string
- return
-
-bail=False; dryrun=False; extrahelp=False; quiet = False
-image=''; ramdisk=''; builder_fn='linux'; restore=0; state_file=''
-mem_size=0; domain_name=''; vfr_ipaddr=[];
-vbd_expert='rr'; auto_restart=False;
-vbd_list = []; cmdline_ip = ''; cmdline_root=''; cmdline_extra=''
-pci_device_list = []; console_port = -1
-auto_console = False
-config_from_file = False
-
-##### Determine location of defaults file
-#####
-
-try:
- opts, args = getopt.getopt(sys.argv[1:], "h?nqcf:F:D:k:r:b:m:N:a:e:d:i:I:R:E:L:" )
-
- for opt in opts:
- if opt[0] == '-f': config_file= opt[1]
- if opt[0] == '-h' or opt[0] == '-?' : bail=True; extrahelp=True
- if opt[0] == '-n': dryrun=True
- if opt[0] == '-D':
- for o in string.split( opt[1], ';' ):
- (l,r) = string.split( o, '=' )
- exec "%s='%s'" % (l,r)
- if opt[0] == '-q': quiet = True
- if opt[0] == '-L': restore = True; state_file = opt[1]
- if opt[0] == '-F': config_from_file = True; domain_config = opt[1]
-
-
-except getopt.GetoptError:
- bail=True
-
-if not config_from_file:
- try:
- os.stat( config_file )
- except:
- try:
- d = config_dir + config_file
- os.stat( d )
- config_file = d
- except:
- print >> sys.stderr, "Unable to open config file '%s'" % config_file
- bail = True
-
-
-##### Parse the config file
-#####
-
-if not config_from_file:
- if not quiet:
- print "Parsing config file '%s'" % config_file
-
- try:
- execfile ( config_file )
- except (AssertionError,IOError):
- print >>sys.stderr,"Exiting %s" % sys.argv[0]
- bail = True
-
-##### Print out config if necessary
-#####
-
-def bailout():
- global extrahelp
- main_usage()
- config_usage()
- if extrahelp: extra_usage()
- sys.exit(1)
-
-if bail:
- bailout()
-
-##### Parse any command line overrides
-#####
-
-x_vbd_list = []
-x_vfr_ipaddr = []
-
-for opt in opts:
- if opt[0] == '-k': image = opt[1]
- if opt[0] == '-r': ramdisk = opt[1]
- if opt[0] == '-b': builder_fn = opt[1]
- if opt[0] == '-m': mem_size = int(opt[1])
- if opt[0] == '-C': cpu = int(opt[1])
- if opt[0] == '-N': domain_name = opt[1]
- if opt[0] == '-a': auto_restart = answer(opt[1])
- if opt[0] == '-e': vbd_expert = opt[1]
- if opt[0] == '-I': cmdline_ip = opt[1]
- if opt[0] == '-R': cmdline_root = opt[1]
- if opt[0] == '-E': cmdline_extra = opt[1]
- if opt[0] == '-i': x_vfr_ipaddr.append(opt[1])
- if opt[0] == '-c': auto_console = True
- if opt[0] == '-d':
- try:
- vv = string.split(opt[1],';')
- for v in vv:
- (udisk,dev,mode) = string.split(v,',')
- x_vbd_list.append( (udisk,dev,mode) )
- except:
- print >>sys.stderr, "Invalid block device specification : %s" % opt[1]
- sys.exit(1)
-
-if x_vbd_list: vbd_list = x_vbd_list
-if x_vfr_ipaddr: vfr_ipaddr = x_vfr_ipaddr
-
-syslog.openlog('xc_dom_create.py %s' % config_file, 0, syslog.LOG_DAEMON)
-
-def strip(pre, s):
- if s.startswith(pre):
- return s[len(pre):]
- else:
- return s
-
-def make_domain_config():
- global builder_fn, image, ramdisk, mem_size, domain_name
- global cpu
- global cmdline, cmdline_ip, cmdline_root
- global vfr_ipaddr, vbd_list, vbd_expert
-
- config = ['config',
- ['name', domain_name ],
- ['memory', mem_size ],
- ]
- if cpu:
- config.append(['cpu', cpu])
-
- config_image = [ builder_fn ]
- config_image.append([ 'kernel', os.path.abspath(image) ])
- if ramdisk:
- config_image.append([ 'ramdisk', os.path.abspath(ramdisk) ])
- if cmdline_ip:
- cmdline_ip = strip("ip=", cmdline_ip)
- config_image.append(['ip', cmdline_ip])
- if cmdline_root:
- cmdline_root = strip("root=", cmdline_root)
- config_image.append(['root', cmdline_root])
- if cmdline_extra:
- config_image.append(['args', cmdline_extra])
- config.append(['image', config_image ])
-
- config_devs = []
- for (uname, dev, mode) in vbd_list:
- config_vbd = ['vbd',
- ['uname', uname],
- ['dev', dev ],
- ['mode', mode ] ]
- if vbd_expert != 'rr':
- config_vbd.append(['sharing', vbd_expert])
- config_devs.append(['device', config_vbd])
-
- for (bus, dev, func) in pci_device_list:
- config_pci = ['pci',
- ['bus', bus ],
- ['dev', dev ],
- ['func', func] ]
- config_devs.append(['device', config_pci])
-
- # Add one vif with unspecified MAC.
- config_devs.append(['device', ['vif']])
-
- config += config_devs
-
- config_vfr = ['vfr']
- idx = 0 # No way of saying which IP is for which vif?
- for ip in vfr_ipaddr:
- config_vfr.append(['vif', ['id', idx], ['ip', ip]])
-
- config.append(config_vfr)
- return config
-
-def parse_config_file(domain_file):
- config = None
- fin = None
- try:
- fin = file(domain_file, "rb")
- config = sxp.parse(fin)
- if len(config) >= 1:
- config = config[0]
- else:
- raise StandardError("Invalid configuration")
- except StandardError, ex:
- print >> sys.stderr, "Error :", ex
- sys.exit(1)
- #finally:
- if fin: fin.close()
- return config
-
-# This function creates, builds and starts a domain, using the values
-# in the global variables, set above. It is used in the subsequent
-# code for starting the new domain and rebooting it if appropriate.
-def make_domain(config):
- """Create, build and start a domain.
- Returns: [int] the ID of the new domain.
- """
- global restore
-
- if restore:
- dominfo = server.xend_domain_restore(state_file, config)
- else:
- dominfo = server.xend_domain_create(config)
-
- dom = int(sxp.child_value(dominfo, 'id'))
- console_info = sxp.child(dominfo, 'console')
- if console_info:
- console_port = int(sxp.child_value(console_info, 'port'))
- else:
- console_port = None
-
- if server.xend_domain_unpause(dom) < 0:
- print "Error starting domain"
- server.xend_domain_halt(dom)
- sys.exit()
-
- return (dom, console_port)
-
-PID_DIR = '/var/run/xendomains/'
-
-def pidfile(dom):
- return PID_DIR + '%d.pid' % dom
-
-def mkpidfile():
- global current_id
- if not os.path.isdir(PID_DIR):
- os.mkdir(PID_DIR)
-
- fd = open(pidfile(current_id), 'w')
- print >> fd, str(os.getpid())
- fd.close()
- return
-
-def rmpidfile():
- global current_id
- os.unlink(pidfile(current_id))
-
-def death_handler(dummy1,dummy2):
- global current_id
- os.unlink(pidfile(current_id))
- output('Auto-restart daemon: daemon PID = %d for domain %d is now exiting'
- % (os.getpid(), current_id))
- sys.exit(0)
- return
-
-#============================================================================
-# The starting / monitoring of the domain actually happens here...
-
-if config_from_file:
- config = parse_config_file(domain_config)
-else:
- config = make_domain_config()
-
-if dryrun:
- print "# %s" % ' '.join(sys.argv)
- PrettyPrint.prettyprint(config)
- sys.exit(0)
-elif quiet:
- pass
-else:
- PrettyPrint.prettyprint(config)
-
-# start the domain and record its ID number
-(current_id, current_port) = make_domain(config)
-
-def start_msg(prefix, dom, port):
- output(prefix + "VM started in domain %d" % dom)
- if port:
- output(prefix + "Console I/O available on TCP port %d." % port)
-
-start_msg('', current_id, current_port)
-
-if current_port and auto_console:
- xenctl.console_client.connect('127.0.0.1', current_port)
-
-# if the auto_restart flag is set then keep polling to see if the domain is
-# alive - restart if it is not by calling make_domain() again (it's necessary
-# to update the id variable, since the new domain may have a new ID)
-
-#todo: Replace this - get xend to watch them.
-if auto_restart:
- ARD = "Auto-restart daemon: "
- # turn ourselves into a background daemon
- try:
- pid = os.fork()
- if pid > 0:
- sys.exit(0)
- os.setsid()
- pid = os.fork()
- if pid > 0:
- output(ARD + 'PID = %d' % pid)
- sys.exit(0)
- signal.signal(signal.SIGTERM,death_handler)
- except OSError:
- print >> sys.stderr, ARD+'Startup failed'
- sys.exit(1)
-
- mkpidfile()
-
- while True:
- time.sleep(1)
- # todo: use new interface
- info = xc.domain_getinfo(current_id, 1)
- if info == [] or info[0]['dom'] != current_id:
- output(ARD + "Domain %d terminated, restarting VM in new domain"
- % current_id)
- rmpidfile()
- (current_id, current_port) = make_domain()
- mkpidfile()
- start_msg(ARD, current_id, current_port)
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "allocate.h"
-
-/** @file
- * Support for allocating memory.
- * Usable from user code or kernel code (with __KERNEL__ defined).
- * In user code will use GC if USE_GC is defined.
- */
-
-#ifdef __KERNEL__
-/*----------------------------------------------------------------------------*/
-# include <linux/config.h>
-# include <linux/slab.h>
-# include <linux/string.h>
-# include <linux/types.h>
-
-# define DEFAULT_TYPE 0
-# define MALLOC(n, type) kmalloc(n, type)
-# define FREE(ptr) kfree(ptr)
-
-/*----------------------------------------------------------------------------*/
-#else /* ! __KERNEL__ */
-
-# include <stdlib.h>
-# include <string.h>
-
-# define DEFAULT_TYPE 0
-
-#ifdef USE_GC
-# include "gc.h"
-# define MALLOC(n, typ) GC_malloc(n)
-# define FREE(ptr) (ptr=NULL)
-//typedef void *GC_PTR;
-//GC_PTR (*GC_oom_fn)(size_t n);
-#else
-# define MALLOC(n, type) malloc(n)
-# define FREE(ptr) free(ptr)
-#endif
-
-/*----------------------------------------------------------------------------*/
-#endif
-
-/** Function to call when memory cannot be allocated. */
-AllocateFailedFn *allocate_failed_fn = NULL;
-
-/** Allocate memory and zero it.
- * The type is only relevant when calling from kernel code,
- * from user code it is ignored.
- * In kernel code the values accepted by kmalloc can be used:
- * GFP_USER, GFP_ATOMIC, GFP_KERNEL.
- *
- * @param size number of bytes to allocate
- * @param type memory type to allocate (kernel only)
- * @return pointer to the allocated memory or zero
- * if malloc failed
- */
-void *allocate_type(int size, int type){
- void *p = MALLOC(size, type);
- if(p){
- memzero(p, size);
- } else if(allocate_failed_fn){
- allocate_failed_fn(size, type);
- }
- return p;
-}
-
-/** Allocate memory and zero it.
- *
- * @param size number of bytes to allocate
- * @return pointer to the allocated memory or zero
- * if malloc failed
- */
-void *allocate(int size){
- return allocate_type(size, DEFAULT_TYPE);
-}
-
-/** Free memory allocated by allocate().
- * No-op if 'p' is null.
- *
- * @param p memory to free
- */
-void deallocate(void *p){
- if(p){
- FREE(p);
- }
-}
-
-/** Set bytes to zero.
- * No-op if 'p' is null.
- *
- * @param p memory to zero
- * @param size number of bytes to zero
- */
-void memzero(void *p, int size){
- if(p){
- memset(p, 0, (size_t)size);
- }
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XEN_LIB_ALLOCATE_H_
-#define _XEN_LIB_ALLOCATE_H_
-
-/** Allocate memory for a given type, and cast. */
-#define ALLOCATE(ctype) (ctype *)allocate(sizeof(ctype))
-
-/** Allocate memory for a given type, and cast. */
-#define ALLOCATE_TYPE(ctype, type) (ctype *)allocate(sizeof(ctype))
-
-extern void *allocate_type(int size, int type);
-extern void *allocate(int size);
-extern void deallocate(void *);
-extern void memzero(void *p, int size);
-
-typedef void AllocateFailedFn(int size, int type);
-extern AllocateFailedFn *allocate_failed_fn;
-
-#endif /* _XEN_LIB_ALLOCATE_H_ */
-
-
-
-
-
-
-
-
-
+++ /dev/null
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _XEN_LIB_DEBUG_H_
-#define _XEN_LIB_DEBUG_H_
-
-#ifndef MODULE_NAME
-#define MODULE_NAME ""
-#endif
-
-#ifdef __KERNEL__
-#include <linux/config.h>
-#include <linux/kernel.h>
-
-#ifdef DEBUG
-
-#define dprintf(fmt, args...) printk(KERN_DEBUG "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
-#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
-#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
-#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
-
-#else
-
-#define dprintf(fmt, args...) do {} while(0)
-#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME fmt, ##args)
-#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME fmt, ##args)
-#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME fmt, ##args)
-
-#endif
-
-#else
-
-#include <stdio.h>
-
-#ifdef DEBUG
-
-#define dprintf(fmt, args...) fprintf(stdout, "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
-#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
-#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
-#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
-
-#else
-
-#define dprintf(fmt, args...) do {} while(0)
-#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME fmt, ##args)
-#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME fmt, ##args)
-#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME fmt, ##args)
-
-#endif
-
-#endif
-
-/** Print format for an IP address.
- * See NIPQUAD(), HIPQUAD()
- */
-#define IPFMT "%u.%u.%u.%u"
-
-#endif /* ! _XEN_LIB_DEBUG_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library is
- * distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef __KERNEL__
-#include <linux/errno.h>
-#else
-#include <errno.h>
-#endif
-
-#include "sys_string.h"
-#include "enum.h"
-
-/** Map an enum name to its value using a table.
- *
- * @param name enum name
- * @param defs enum definitions
- * @return enum value or -1 if not known
- */
-int enum_name_to_val(char *name, EnumDef *defs){
- int val = -1;
- for(; defs->name; defs++){
- if(!strcmp(defs->name, name)){
- val = defs->val;
- break;
- }
- }
- return val;
-}
-
-/** Map an enum value to its name using a table.
- *
- * @param val enum value
- * @param defs enum definitions
- * @param defs_n number of definitions
- * @return enum name or NULL if not known
- */
-char *enum_val_to_name(int val, EnumDef *defs){
- char *name = NULL;
- for(; defs->name; defs++){
- if(val == defs->val){
- name = defs->name;
- break;
- }
- }
- return name;
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library is
- * distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XEN_LIB_ENUM_H_
-#define _XEN_LIB_ENUM_H_
-
-/** Mapping of an enum value to a name. */
-typedef struct EnumDef {
- int val;
- char *name;
-} EnumDef;
-
-extern int enum_name_to_val(char *name, EnumDef *defs);
-extern char *enum_val_to_name(int val, EnumDef *defs);
-
-#endif /* _XEN_LIB_ENUM_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * An IOStream implementation using FILE*.
- */
-#ifndef __KERNEL__
-#include <stdio.h>
-#include <stdlib.h>
-#include "allocate.h"
-#include "file_stream.h"
-
-static int file_read(IOStream *s, void *buf, size_t n);
-static int file_write(IOStream *s, const void *buf, size_t n);
-static int file_error(IOStream *s);
-static int file_close(IOStream *s);
-static void file_free(IOStream *s);
-static int file_flush(IOStream *s);
-
-/** Methods used by a FILE* IOStream. */
-static const IOMethods file_methods = {
- read: file_read,
- write: file_write,
- error: file_error,
- close: file_close,
- free: file_free,
- flush: file_flush,
-};
-
-/** IOStream for stdin. */
-static IOStream _iostdin = {
- methods: &file_methods,
- data: (void*)1,
-};
-
-/** IOStream for stdout. */
-static IOStream _iostdout = {
- methods: &file_methods,
- data: (void*)2,
-};
-
-/** IOStream for stderr. */
-static IOStream _iostderr = {
- methods: &file_methods,
- data: (void*)3,
-};
-
-/** IOStream for stdin. */
-IOStream *iostdin = &_iostdin;
-
-/** IOStream for stdout. */
-IOStream *iostdout = &_iostdout;
-
-/** IOStream for stderr. */
-IOStream *iostderr = &_iostderr;
-
-/** Get the underlying FILE*.
- *
- * @param s file stream
- * @return the stream s wraps
- */
-static inline FILE *get_file(IOStream *s){
- switch((long)s->data){
- case 1: s->data = stdin; break;
- case 2: s->data = stdout; break;
- case 3: s->data = stderr; break;
- }
- return (FILE*)s->data;
-}
-
-/** Control buffering on the underlying stream, like setvbuf().
- *
- * @param io file stream
- * @param buf buffer
- * @param mode buffering mode (see man setvbuf())
- * @param size buffer size
- * @return 0 on success, non-zero otherwise
- */
-int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size){
- return setvbuf(get_file(io), buf, mode, size);
-}
-
-/** Write to the underlying stream using fwrite();
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to write
- * @return number of bytes written
- */
-static int file_write(IOStream *s, const void *buf, size_t n){
- return fwrite(buf, 1, n, get_file(s));
-}
-
-/** Read from the underlying stream using fread();
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to read
- * @return number of bytes read
- */
-static int file_read(IOStream *s, void *buf, size_t n){
- return fread(buf, 1, n, get_file(s));
-}
-
-/** Fush the underlying stream using fflush().
- *
- * @param s file stream
- * @return 0 on success, error code otherwise
- */
-static int file_flush(IOStream *s){
- return fflush(get_file(s));
-}
-
-/** Check if a stream has an error.
- *
- * @param s file stream
- * @return 1 if has an error, 0 otherwise
- */
-static int file_error(IOStream *s){
- return ferror(get_file(s));
-}
-
-/** Close a file stream.
- *
- * @param s file stream to close
- * @return result of the close
- */
-static int file_close(IOStream *s){
- return fclose(get_file(s));
-}
-
-/** Free a file stream.
- *
- * @param s file stream
- */
-static void file_free(IOStream *s){
- // Do nothing - fclose does it all?
-}
-
-/** Create an IOStream for a stream.
- *
- * @param f stream to wrap
- * @return new IOStream using f for i/o
- */
-IOStream *file_stream_new(FILE *f){
- IOStream *io = ALLOCATE(IOStream);
- if(io){
- io->methods = &file_methods;
- io->data = (void*)f;
- }
- return io;
-}
-
-/** IOStream version of fopen().
- *
- * @param file name of the file to open
- * @param flags giving the mode to open in (as for fopen())
- * @return new stream for the open file, or 0 if failed
- */
-IOStream *file_stream_fopen(const char *file, const char *flags){
- IOStream *io = 0;
- FILE *fin = fopen(file, flags);
- if(fin){
- io = file_stream_new(fin);
- if(!io){
- fclose(fin);
- //free(fin); // fclose frees ?
- }
- }
- return io;
-}
-
-/** IOStream version of fdopen().
- *
- * @param fd file descriptor
- * @param flags giving the mode to open in (as for fdopen())
- * @return new stream for the open file, or 0 if failed
- */
-IOStream *file_stream_fdopen(int fd, const char *flags){
- IOStream *io = 0;
- FILE *fin = fdopen(fd, flags);
- if(fin){
- io = file_stream_new(fin);
- }
- return io;
-}
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XEN_LIB_FILE_STREAM_H_
-#define _XEN_LIB_FILE_STREAM_H_
-
-#ifndef __KERNEL__
-#include "iostream.h"
-#include <stdio.h>
-
-extern IOStream *file_stream_new(FILE *f);
-extern IOStream *file_stream_fopen(const char *file, const char *flags);
-extern IOStream *file_stream_fdopen(int fd, const char *flags);
-extern IOStream get_stream_stdout(void);
-extern IOStream get_stream_stderr(void);
-extern IOStream get_stream_stdin(void);
-
-extern int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size);
-#endif
-#endif /* !_XEN_LIB_FILE_STREAM_H_ */
+++ /dev/null
-/* $Id: gzip_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */
-/*
- * Copyright (C) 2003 Hewlett-Packard Company.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * An IOStream implementation using zlib gzFile to provide
- * compression and decompression.
- */
-#ifndef __KERNEL__
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "zlib.h"
-
-#include "allocate.h"
-#include "gzip_stream.h"
-
-static int gzip_read(IOStream *s, void *buf, size_t n);
-static int gzip_write(IOStream *s, const void *buf, size_t n);
-static int gzip_error(IOStream *s);
-static int gzip_close(IOStream *s);
-static void gzip_free(IOStream *s);
-static int gzip_flush(IOStream *s);
-
-/** Methods used by a gzFile* IOStream. */
-static const IOMethods gzip_methods = {
- read: gzip_read,
- write: gzip_write,
- error: gzip_error,
- close: gzip_close,
- free: gzip_free,
- flush: gzip_flush,
-};
-
-/** Get the underlying gzFile*.
- *
- * @param s gzip stream
- * @return the stream s wraps
- */
-static inline gzFile get_gzfile(IOStream *s){
- return (gzFile)s->data;
-}
-
-/** Write to the underlying stream.
- *
- * @param stream destination
- * @param buf data
- * @param n number of bytes to write
- * @return number of bytes written
- */
-static int gzip_write(IOStream *s, const void *buf, size_t n){
- return gzwrite(get_gzfile(s), (void*)buf, n);
-}
-
-/** Read from the underlying stream.
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to read
- * @return number of bytes read
- */
-static int gzip_read(IOStream *s, void *buf, size_t n){
- return gzread(get_gzfile(s), buf, n);
-}
-
-/** Flush the underlying stream.
- *
- * @param s gzip stream
- * @return 0 on success, error code otherwise
- */
-static int gzip_flush(IOStream *s){
- //return gzflush(get_gzfile(s), Z_NO_FLUSH);
- return gzflush(get_gzfile(s), Z_SYNC_FLUSH);
- //return gzflush(get_gzfile(s), Z_FULL_FLUSH);
-}
-
-/** Check if a stream has an error.
- *
- * @param s gzip stream
- * @return 1 if has an error, 0 otherwise
- */
-static int gzip_error(IOStream *s){
- int err;
- gzFile *gz = get_gzfile(s);
- gzerror(gz, &err);
- return (err == Z_ERRNO ? 1 /* ferror(gzfile(gz)) */ : err);
-}
-
-/** Close a gzip stream.
- *
- * @param s gzip stream to close
- * @return result of the close
- */
-static int gzip_close(IOStream *s){
- return gzclose(get_gzfile(s));
-}
-
-/** Free a gzip stream.
- *
- * @param s gzip stream
- */
-static void gzip_free(IOStream *s){
- // Do nothing - fclose does it all?
-}
-
-/** Create an IOStream for a gzip stream.
- *
- * @param f stream to wrap
- * @return new IOStream using f for i/o
- */
-IOStream *gzip_stream_new(gzFile *f){
- IOStream *io = ALLOCATE(IOStream);
- if(io){
- io->methods = &gzip_methods;
- io->data = (void*)f;
- }
- return io;
-}
-
-/** IOStream version of fopen().
- *
- * @param file name of the file to open
- * @param flags giving the mode to open in (as for fopen())
- * @return new stream for the open file, or NULL if failed
- */
-IOStream *gzip_stream_fopen(const char *file, const char *flags){
- IOStream *io = NULL;
- gzFile *fgz;
- fgz = gzopen(file, flags);
- if(fgz){
- io = gzip_stream_new(fgz);
- if(!io){
- gzclose(fgz);
- //free(fgz); // gzclose frees ?
- }
- }
- return io;
-}
-
-/** IOStream version of fdopen().
- *
- * @param fd file descriptor
- * @param flags giving the mode to open in (as for fdopen())
- * @return new stream for the open file, or NULL if failed
- */
-IOStream *gzip_stream_fdopen(int fd, const char *flags){
- IOStream *io = NULL;
- gzFile *fgz;
- fgz = gzdopen(fd, flags);
- if(fgz){
- io = gzip_stream_new(fgz);
- }
- return io;
-}
-#endif
+++ /dev/null
-#/* $Id: gzip_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */
-/*
- * Copyright (C) 2003 Hewlett-Packard Company.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _SP_GZIP_STREAM_H_
-#define _SP_GZIP_STREAM_H_
-
-#ifndef __KERNEL__
-#include "iostream.h"
-#include "zlib.h"
-
-extern IOStream *gzip_stream_new(gzFile *f);
-extern IOStream *gzip_stream_fopen(const char *file, const char *flags);
-extern IOStream *gzip_stream_fdopen(int fd, const char *flags);
-#endif
-#endif /* !_SP_FILE_STREAM_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef __KERNEL__
-# include <linux/config.h>
-# include <linux/module.h>
-# include <linux/kernel.h>
-# include <linux/errno.h>
-#else
-# include <errno.h>
-# include <stddef.h>
-#endif
-
-//#include <limits.h>
-
-#include "allocate.h"
-#include "hash_table.h"
-
-/** @file
- * Base support for hashtables.
- *
- * Hash codes are reduced modulo the number of buckets to index tables,
- * so there is no need for hash functions to limit the range of hashcodes.
- * In fact it is assumed that hashcodes do not change when the number of
- * buckets in the table changes.
- */
-
-/*==========================================================================*/
-/** Number of bits in half a word. */
-//#if __WORDSIZE == 64
-//#define HALF_WORD_BITS 32
-//#else
-#define HALF_WORD_BITS 16
-//#endif
-
-/** Mask for lo half of a word. On 32-bit this is
- * (1<<16) - 1 = 65535 = 0xffff
- * It's 4294967295 = 0xffffffff on 64-bit.
- */
-#define LO_HALF_MASK ((1 << HALF_WORD_BITS) - 1)
-
-/** Get the lo half of a word. */
-#define LO_HALF(x) ((x) & LO_HALF_MASK)
-
-/** Get the hi half of a word. */
-#define HI_HALF(x) ((x) >> HALF_WORD_BITS)
-
-/** Do a full hash on both inputs, using DES-style non-linear scrambling.
- * Both inputs are replaced with the results of the hash.
- *
- * @param pleft input/output word
- * @param pright input/output word
- */
-void pseudo_des(unsigned long *pleft, unsigned long *pright){
- // Bit-rich mixing constant.
- static const unsigned long a_mixer[] = {
- 0xbaa96887L, 0x1e17d32cL, 0x03bcdc3cL, 0x0f33d1b2L, };
-
- // Bit-rich mixing constant.
- static const unsigned long b_mixer[] = {
- 0x4b0f3b58L, 0xe874f0c3L, 0x6955c5a6L, 0x55a7ca46L, };
-
- // Number of iterations - must be 2 or 4.
- static const int ncycle = 4;
- //static const int ncycle = 2;
-
- unsigned long left = *pleft, right = *pright;
- unsigned long v, v_hi, v_lo;
- int i;
-
- for(i=0; i<ncycle; i++){
- // Flip some bits in right to get v.
- v = right;
- v ^= a_mixer[i];
- // Get lo and hi halves of v.
- v_lo = LO_HALF(v);
- v_hi = HI_HALF(v);
- // Non-linear mix of the halves of v.
- v = ((v_lo * v_lo) + ~(v_hi * v_hi));
- // Swap the halves of v.
- v = (HI_HALF(v) | (LO_HALF(v) << HALF_WORD_BITS));
- // Flip some bits.
- v ^= b_mixer[i];
- // More non-linear mixing.
- v += (v_lo * v_hi);
- v ^= left;
- left = right;
- right = v;
- }
- *pleft = left;
- *pright = right;
-}
-
-/** Hash a string.
- *
- * @param s input to hash
- * @return hashcode
- */
-Hashcode hash_string(char *s){
- Hashcode h = 0;
- if(s){
- for( ; *s; s++){
- h = hash_2ul(h, *s);
- }
- }
- return h;
-}
-
-/** Get the bucket for a hashcode in a hash table.
- *
- * @param table to get bucket from
- * @param hashcode to get bucket for
- * @return bucket
- */
-inline HTBucket * get_bucket(HashTable *table, Hashcode hashcode){
- return table->buckets + (hashcode % table->buckets_n);
-}
-
-/** Initialize a hash table.
- * Can be safely called more than once.
- *
- * @param table to initialize
- */
-void HashTable_init(HashTable *table){
- int i;
-
- if(!table->init_done){
- table->init_done = 1;
- table->next_id = 0;
- for(i=0; i<table->buckets_n; i++){
- HTBucket *bucket = get_bucket(table, i);
- bucket->head = 0;
- bucket->count = 0;
- }
- table->entry_count = 0;
- }
-}
-
-/** Allocate a new hashtable.
- * If the number of buckets is not positive the default is used.
- * The number of buckets should usually be prime.
- *
- * @param buckets_n number of buckets
- * @return new hashtable or null
- */
-HashTable *HashTable_new(int buckets_n){
- HashTable *z = ALLOCATE(HashTable);
- if(!z) goto exit;
- if(buckets_n <= 0){
- buckets_n = HT_BUCKETS_N;
- }
- z->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
- if(!z->buckets){
- deallocate(z);
- z = 0;
- goto exit;
- }
- z->buckets_n = buckets_n;
- HashTable_init(z);
- exit:
- return z;
-}
-
-/** Free a hashtable.
- * Any entries are removed and freed.
- *
- * @param h hashtable (ignored if null)
- */
-void HashTable_free(HashTable *h){
- if(h){
- HashTable_clear(h);
- deallocate(h->buckets);
- deallocate(h);
- }
-}
-
-/** Push an entry on the list in the bucket for a given hashcode.
- *
- * @param table to add entry to
- * @param hashcode for the entry
- * @param entry to add
- */
-static inline void push_on_bucket(HashTable *table, Hashcode hashcode,
- HTEntry *entry){
- HTBucket *bucket;
- HTEntry *old_head;
-
- bucket = get_bucket(table, hashcode);
- old_head = bucket->head;
- bucket->count++;
- bucket->head = entry;
- entry->next = old_head;
-}
-
-/** Change the number of buckets in a hashtable.
- * No-op if the number of buckets is not positive.
- * Existing entries are reallocated to buckets based on their hashcodes.
- * The table is unmodified if the number of buckets cannot be changed.
- *
- * @param table hashtable
- * @param buckets_n new number of buckets
- * @return 0 on success, error code otherwise
- */
-int HashTable_set_buckets_n(HashTable *table, int buckets_n){
- int err = 0;
- HTBucket *old_buckets = table->buckets;
- int old_buckets_n = table->buckets_n;
- int i;
-
- if(buckets_n <= 0){
- err = -EINVAL;
- goto exit;
- }
- table->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
- if(!table->buckets){
- err = -ENOMEM;
- table->buckets = old_buckets;
- goto exit;
- }
- table->buckets_n = buckets_n;
- for(i=0; i<old_buckets_n; i++){
- HTBucket *bucket = old_buckets + i;
- HTEntry *entry, *next;
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- push_on_bucket(table, entry->hashcode, entry);
- }
- }
- deallocate(old_buckets);
- exit:
- return err;
-}
-
-/** Adjust the number of buckets so the table is neither too full nor too empty.
- * The table is unmodified if adjusting fails.
- *
- * @param table hash table
- * @param buckets_min minimum number of buckets (use default if 0 or negative)
- * @return 0 on success, error code otherwise
- */
-int HashTable_adjust(HashTable *table, int buckets_min){
- int buckets_n = 0;
- int err = 0;
- if(buckets_min <= 0) buckets_min = HT_BUCKETS_N;
- if(table->entry_count >= table->buckets_n){
- // The table is dense - expand it.
- buckets_n = 2 * table->buckets_n;
- } else if((table->buckets_n > buckets_min) &&
- (4 * table->entry_count < table->buckets_n)){
- // The table is more than minimum size and sparse - shrink it.
- buckets_n = 2 * table->entry_count;
- if(buckets_n < buckets_min) buckets_n = buckets_min;
- }
- if(buckets_n){
- err = HashTable_set_buckets_n(table, buckets_n);
- }
- return err;
-}
-
-/** Allocate a new entry for a given value.
- *
- * @param value to put in the entry
- * @return entry, or 0 on failure
- */
-HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value){
- HTEntry *z = ALLOCATE(HTEntry);
- if(z){
- z->hashcode = hashcode;
- z->key = key;
- z->value = value;
- }
- return z;
-}
-
-/** Free an entry.
- *
- * @param z entry to free
- */
-inline void HTEntry_free(HTEntry *z){
- if(z){
- deallocate(z);
- }
-}
-
-/** Free an entry in a hashtable.
- * The table's entry_free_fn is used is defined, otherwise
- * the HTEntry itself is freed.
- *
- * @param table hashtable
- * @param entry to free
- */
-inline void HashTable_free_entry(HashTable *table, HTEntry *entry){
- if(!entry)return;
- if(table && table->entry_free_fn){
- table->entry_free_fn(table, entry);
- } else {
- HTEntry_free(entry);
- }
-}
-
-/** Get the first entry satisfying a test from the bucket for the
- * given hashcode.
- *
- * @param table to look in
- * @param hashcode indicates the bucket
- * @param test_fn test to apply to elements
- * @param arg first argument to calls to test_fn
- * @return entry found, or 0
- */
-inline HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
- TableTestFn *test_fn, TableArg arg){
- HTBucket *bucket;
- HTEntry *entry = 0;
- HTEntry *next;
-
- bucket = get_bucket(table, hashcode);
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- if(test_fn(arg, table, entry)){
- break;
- }
- }
- return entry;
-}
-
-/** Test hashtable keys for equality.
- * Uses the table's key_equal_fn if defined, otherwise pointer equality.
- *
- * @param key1 key to compare
- * @param key2 key to compare
- * @return 1 if equal, 0 otherwise
- */
-inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){
- return (table->key_equal_fn ? table->key_equal_fn(key1, key2) : key1==key2);
-}
-
-/** Compute the hashcode of a hashtable key.
- * The table's key_hash_fn is used if defined, otherwise the address of
- * the key is hashed.
- *
- * @param table hashtable
- * @param key to hash
- * @return hashcode
- */
-inline Hashcode HashTable_key_hash(HashTable *table, void *key){
- return (table->key_hash_fn ? table->key_hash_fn(key) : hash_ul((unsigned long)key));
-}
-
-/** Test if an entry has a given key.
- *
- * @param arg containing key to test for
- * @param table the entry is in
- * @param entry to test
- * @return 1 if the entry has the key, 0 otherwise
- */
-static inline int has_key(TableArg arg, HashTable *table, HTEntry *entry){
- return HashTable_key_equal(table, arg.ptr, entry->key);
-}
-
-/** Get an entry with a given key.
- *
- * @param table to search
- * @param key to look for
- * @return entry if found, null otherwise
- */
-#if 0
-inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
- TableArg arg = { ptr: key };
- return HashTable_find_entry(table, HashTable_key_hash(table, key), has_key, arg);
-}
-#else
-inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
- Hashcode hashcode;
- HTBucket *bucket;
- HTEntry *entry = 0;
- HTEntry *next;
-
- hashcode = HashTable_key_hash(table, key);
- bucket = get_bucket(table, hashcode);
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- if(HashTable_key_equal(table, key, entry->key)){
- break;
- }
- }
- return entry;
-}
-#endif
-
-/** Get the value of an entry with a given key.
- *
- * @param table to search
- * @param key to look for
- * @return value if an entry was found, null otherwise
- */
-inline void * HashTable_get(HashTable *table, void *key){
- HTEntry *entry = HashTable_get_entry(table, key);
- return (entry ? entry->value : 0);
-}
-
-/** Print the buckets in a table.
- *
- * @param table to print
- */
-void show_buckets(HashTable *table, IOStream *io){
- int i,j ;
- IOStream_print(io, "entry_count=%d buckets_n=%d\n", table->entry_count, table->buckets_n);
- for(i=0; i<table->buckets_n; i++){
- if(0 || table->buckets[i].count>0){
- IOStream_print(io, "bucket %3d %3d %10p ", i,
- table->buckets[i].count,
- table->buckets[i].head);
- for(j = table->buckets[i].count; j>0; j--){
- IOStream_print(io, "+");
- }
- IOStream_print(io, "\n");
- }
- }
- HashTable_print(table, io);
-}
-
-/** Print an entry in a table.
- *
- * @param entry to print
- * @param arg a pointer to an IOStream to print to
- * @return 0
- */
-static int print_entry(TableArg arg, HashTable *table, HTEntry *entry){
- IOStream *io = (IOStream*)arg.ptr;
- IOStream_print(io, " b=%4lx h=%08lx i=%08lx |-> e=%8p k=%8p v=%8p\n",
- entry->hashcode % table->buckets_n,
- entry->hashcode,
- entry->index,
- entry, entry->key, entry->value);
- return 0;
-}
-
-/** Print a hash table.
- *
- * @param table to print
- */
-void HashTable_print(HashTable *table, IOStream *io){
- IOStream_print(io, "{\n");
- HashTable_map(table, print_entry, (TableArg){ ptr: io });
- IOStream_print(io, "}\n");
-}
-/*==========================================================================*/
-
-/** Get the next entry id to use for a table.
- *
- * @param table hash table
- * @return non-zero entry id
- */
-static inline unsigned long get_next_id(HashTable *table){
- unsigned long id;
-
- if(table->next_id == 0){
- table->next_id = 1;
- }
- id = table->next_id++;
- return id;
-}
-
-/** Add an entry to the bucket for the
- * given hashcode.
- *
- * @param table to insert in
- * @param hashcode indicates the bucket
- * @param key to add an entry for
- * @param value to add an entry for
- * @return entry on success, 0 on failure
- */
-inline HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value){
- HTEntry *entry = HTEntry_new(hashcode, key, value);
- if(entry){
- entry->index = get_next_id(table);
- push_on_bucket(table, hashcode, entry);
- table->entry_count++;
- }
- return entry;
-}
-
-/** Move the front entry for a bucket to the correct point in the bucket order as
- * defined by the order function. If this is called every time a new entry is added
- * the bucket will be maintained in sorted order.
- *
- * @param table to modify
- * @param hashcode indicates the bucket
- * @param order entry comparison function
- * @return 0 if an entry was moved, 1 if not
- */
-int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order){
- HTEntry *new_entry = NULL, *prev = NULL, *entry = NULL;
- HTBucket *bucket;
- int err = 1;
-
- bucket = get_bucket(table, hashcode);
- new_entry = bucket->head;
- if(!new_entry || !new_entry->next) goto exit;
- for(entry = new_entry->next; entry; prev = entry, entry = entry->next){
- if(order(new_entry, entry) <= 0) break;
- }
- if(prev){
- err = 0;
- bucket->head = new_entry->next;
- new_entry->next = entry;
- prev->next = new_entry;
- }
- exit:
- return err;
-}
-
-/** Add an entry to a hashtable.
- * The entry is added to the bucket for its key's hashcode.
- *
- * @param table to insert in
- * @param key to add an entry for
- * @param value to add an entry for
- * @return entry on success, 0 on failure
- */
-inline HTEntry * HashTable_add(HashTable *table, void *key, void *value){
- return HashTable_add_entry(table, HashTable_key_hash(table, key), key, value);
-}
-
-
-/** Remove entries satisfying a test from the bucket for the
- * given hashcode.
- *
- * @param table to remove from
- * @param hashcode indicates the bucket
- * @param test_fn test to apply to elements
- * @param arg first argument to calls to test_fn
- * @return number of entries removed
- */
-inline int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
- TableTestFn *test_fn, TableArg arg){
- HTBucket *bucket;
- HTEntry *entry, *prev = 0, *next;
- int removed_count = 0;
-
- bucket = get_bucket(table, hashcode);
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- if(test_fn(arg, table, entry)){
- if(prev){
- prev->next = next;
- } else {
- bucket->head = next;
- }
- bucket->count--;
- table->entry_count--;
- removed_count++;
- HashTable_free_entry(table, entry);
- entry = 0;
- }
- prev = entry;
- }
- return removed_count;
-}
-
-/** Remove entries with a given key.
- *
- * @param table to remove from
- * @param key of entries to remove
- * @return number of entries removed
- */
-inline int HashTable_remove(HashTable *table, void *key){
-#if 1
- Hashcode hashcode;
- HTBucket *bucket;
- HTEntry *entry, *prev = 0, *next;
- int removed_count = 0;
-
- hashcode = HashTable_key_hash(table, key);
- bucket = get_bucket(table, hashcode);
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- if(HashTable_key_equal(table, key, entry->key)){
- if(prev){
- prev->next = next;
- } else {
- bucket->head = next;
- }
- bucket->count--;
- table->entry_count--;
- removed_count++;
- HashTable_free_entry(table, entry);
- entry = 0;
- }
- prev = entry;
- }
- return removed_count;
-#else
- return HashTable_remove_entry(table, HashTable_key_hash(table, key),
- has_key, (TableArg){ ptr: key});
-#endif
-}
-
-/** Remove (and free) all the entries in a bucket.
- *
- * @param bucket to clear
- */
-static inline void bucket_clear(HashTable *table, HTBucket *bucket){
- HTEntry *entry, *next;
-
- for(entry = bucket->head; entry; entry = next){
- next = entry->next;
- HashTable_free_entry(table, entry);
- }
- bucket->head = 0;
- table->entry_count -= bucket->count;
- bucket->count = 0;
-}
-
-/** Remove (and free) all the entries in a table.
- *
- * @param table to clear
- */
-void HashTable_clear(HashTable *table){
- int i, n = table->buckets_n;
-
- for(i=0; i<n; i++){
- bucket_clear(table, table->buckets + i);
- }
-}
+++ /dev/null
-/* $Id: hash_table.h,v 1.1 2004/03/30 16:21:26 mjw Exp $ */
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XEN_LIB_HASH_TABLE_H_
-#define _XEN_LIB_HASH_TABLE_H_
-
-#include "iostream.h"
-
-typedef unsigned long Hashcode;
-
-/** Type used to pass parameters to table functions. */
-typedef union TableArg {
- unsigned long ul;
- void *ptr;
-} TableArg;
-
-/** An entry in a bucket list. */
-typedef struct HTEntry {
- /** Hashcode of the entry's key. */
- Hashcode hashcode;
- /** Identifier for this entry in the table. */
- int index;
- /** The key for this entry. */
- void *key;
- /** The value in this entry. */
- void *value;
- /** The next entry in the list. */
- struct HTEntry *next;
-} HTEntry;
-
-/** A bucket in a rule table. */
-typedef struct HTBucket {
- /** Number of entries in the bucket. */
- int count;
- /** First entry in the bucket (may be null). */
- HTEntry *head;
-} HTBucket;
-
-/** Default number of buckets in a hash table.
- * You want enough buckets so the lists in the buckets will typically be short.
- * It's a good idea if this is prime, since that will help to spread hashcodes
- * around the table.
- */
-//#define HT_BUCKETS_N 1
-//#define HT_BUCKETS_N 3
-//#define HT_BUCKETS_N 7
-//#define HT_BUCKETS_N 17
-//#define HT_BUCKETS_N 97
-//#define HT_BUCKETS_N 211
-//#define HT_BUCKETS_N 401
-#define HT_BUCKETS_N 1021
-
-typedef struct HashTable HashTable;
-
-/** Type for a function used to select table entries. */
-typedef int TableTestFn(TableArg arg, HashTable *table, HTEntry *entry);
-
-/** Type for a function to map over table entries. */
-typedef int TableMapFn(TableArg arg, HashTable *table, HTEntry *entry);
-
-/** Type for a function to free table entries. */
-typedef void TableFreeFn(HashTable *table, HTEntry *entry);
-
-/** Type for a function to hash table keys. */
-typedef Hashcode TableHashFn(void *key);
-
-/** Type for a function to test table keys for equality. */
-typedef int TableEqualFn(void *key1, void *key2);
-
-/** Type for a function to order table entries. */
-typedef int TableOrderFn(HTEntry *e1, HTEntry *e2);
-
-/** General hash table.
- * A hash table with a list in each bucket.
- * Functions can be supplied for freeing entries, hashing keys, and comparing keys.
- * These all default to 0, when default behaviour treating keys as integers is used.
- */
-struct HashTable {
- /** Flag indicating whether the table has been initialised. */
- int init_done;
- /** Next value for the id field in inserted rules. */
- unsigned long next_id;
- /** Number of buckets in the bucket array. */
- int buckets_n;
- /** Array of buckets, each with its own list. */
- HTBucket *buckets;
- /** Number of entries in the table. */
- int entry_count;
- /** Function to free keys and values in entries. */
- TableFreeFn *entry_free_fn;
- /** Function to hash keys. */
- TableHashFn *key_hash_fn;
- /** Function to compare keys for equality. */
- TableEqualFn *key_equal_fn;
- /** Place for the user of the table to hang extra data. */
- void *user_data;
-};
-
-extern HashTable *HashTable_new(int bucket_n);
-extern void HashTable_free(HashTable *table);
-extern HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value);
-extern void HTEntry_free(HTEntry *entry);
-extern int HashTable_set_bucket_n(HashTable *table, int bucket_n);
-extern void HashTable_clear(HashTable *table);
-extern HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value);
-extern HTEntry * HashTable_get_entry(HashTable *table, void *key);
-extern HTEntry * HashTable_add(HashTable *table, void *key, void *value);
-extern void * HashTable_get(HashTable *table, void *key);
-extern int HashTable_remove(HashTable *table, void *key);
-extern HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
- TableTestFn *test_fn, TableArg arg);
-extern int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
- TableTestFn *test_fn, TableArg arg);
-//extern int HashTable_map(HashTable *table, TableMapFn *map_fn, TableArg arg);
-extern void HashTable_print(HashTable *table, IOStream *out);
-extern int HashTable_set_buckets_n(HashTable *table, int buckets_n);
-extern int HashTable_adjust(HashTable *table, int buckets_min);
-extern void pseudo_des(unsigned long *pleft, unsigned long *pright);
-extern Hashcode hash_string(char *s);
-
-extern int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order);
-
-/** Control whether to use hashing based on DES or simple
- * hashing. DES hashing is `more random' but much more expensive.
- */
-#define HASH_PSEUDO_DES 0
-
-/** Hash a long using a quick and dirty linear congruential random number generator.
- * See `Numerical Recipes in C', Chapter 7, "An Even Quicker Generator".
- *
- * @param a value to hash
- * @return hashed input
- */
-static inline unsigned long lcrng_hash(unsigned long a){
- return (1664525L * a + 1013904223L);
-}
-
-/** Hash an unsigned long.
- *
- * @param a input to hash
- * @return hashcode
- */
-static inline Hashcode hash_ul(unsigned long a){
-#if HASH_PSEUDO_DES
- unsigned long left = a;
- unsigned long right = 0L;
- pseudo_des(&left, &right);
- return right;
-#else
- a = lcrng_hash(a);
- a = lcrng_hash(a);
- return a;
-#endif
-}
-
-/** Hash two unsigned longs together.
- *
- * @param a input to hash
- * @param b input to hash
- * @return hashcode
- */
-static inline Hashcode hash_2ul(unsigned long a, unsigned long b){
-#if HASH_PSEUDO_DES
- unsigned long left = a;
- unsigned long right = b;
- pseudo_des(&left, &right);
- return right;
-#else
- a = lcrng_hash(a);
- a ^= b;
- a = lcrng_hash(a);
- return a;
-#endif
-}
-
-/** Hash a hashcode and an unsigned long together.
- *
- * @param a input hashcode
- * @param b input to hash
- * @return hashcode
- */
-static inline Hashcode hash_hul(Hashcode a, unsigned long b){
-#if HASH_PSEUDO_DES
- unsigned long left = a;
- unsigned long right = b;
- pseudo_des(&left, &right);
- return right;
-#else
- a ^= b;
- a = lcrng_hash(a);
- return a;
-#endif
-}
-
-/** Macro to declare variables for HashTable_for_each() to use.
- *
- * @param entry variable that is set to entries in the table
- */
-#define HashTable_for_decl(entry) \
- HashTable *_var_table; \
- HTBucket *_var_bucket; \
- HTBucket *_var_end; \
- HTEntry *_var_next; \
- HTEntry *entry
-
-/** Macro to iterate over the entries in a hashtable.
- * Must be in a scope where HashTable_for_decl() has been used to declare
- * variables for it to use.
- * The variable 'entry' is iterated over entries in the table.
- * The code produced is syntactically a loop, so it must be followed by
- * a loop body, typically some statements in braces:
- * HashTable_for_each(entry, table){ ...loop body... }
- *
- * HashTable_for_each() and HashTable_for_decl() cannot be used for nested
- * loops as variables will clash.
- *
- * @note The simplest way to code a direct loop over the entries in a hashtable
- * is to use a loop over the buckets, with a nested loop over the entries
- * in a bucket. Using this approach in a macro means the macro contains
- * an opening brace, and calls to it must be followed by 2 braces!
- * To avoid this the code has been restructured so that it is a for loop.
- * So that statements could be used in the test expression of the for loop,
- * we have used the gcc statement expression extension ({ ... }).
- *
- * @param entry variable to iterate over the entries
- * @param table to iterate over (non-null)
- */
-#define HashTable_for_each(entry, table) \
- _var_table = table; \
- _var_bucket = _var_table->buckets; \
- _var_end = _var_bucket + _var_table->buckets_n; \
- for(entry=0, _var_next=0; \
- ({ if(_var_next){ \
- entry = _var_next; \
- _var_next = entry->next; \
- } else { \
- while(_var_bucket < _var_end){ \
- entry = _var_bucket->head; \
- _var_bucket++; \
- if(entry){ \
- _var_next = entry->next; \
- break; \
- } \
- } \
- }; \
- entry; }); \
- entry = _var_next )
-
-/** Map a function over the entries in a table.
- * Mapping stops when the function returns a non-zero value.
- * Uses the gcc statement expression extension ({ ... }).
- *
- * @param table to map over
- * @param fn function to apply to entries
- * @param arg first argument to call the function with
- * @return 0 if fn always returned 0, first non-zero value otherwise
- */
-#define HashTable_map(table, fn, arg) \
- ({ HashTable_for_decl(_var_entry); \
- TableArg _var_arg = arg; \
- int _var_value = 0; \
- HashTable_for_each(_var_entry, table){ \
- if((_var_value = fn(_var_arg, _var_table, _var_entry))) break; \
- } \
- _var_value; })
-
-/** Cast x to the type for a key or value in a hash table.
- * This avoids compiler warnings when using short integers
- * as keys or values (especially on 64-bit platforms).
- */
-#define HKEY(x) ((void*)(unsigned long)(x))
-
-/** Cast x from the type for a key or value in a hash table.
- * to an unsigned long. This avoids compiler warnings when using
- * short integers as keys or values (especially on 64-bit platforms).
- */
-#define HVAL(x) ((unsigned long)(x))
-
-#endif /* !_XEN_LIB_HASH_TABLE_H_ */
+++ /dev/null
-#include "iostream.h"
-#include "sys_string.h"
-
-/** Print on a stream, like vfprintf().
- *
- * @param stream to print to
- * @param format for the print (as fprintf())
- * @param args arguments to print
- * @return result code from the print
- */
-int IOStream_vprint(IOStream *stream, const char *format, va_list args){
- char buffer[1024];
- int k = sizeof(buffer), n;
-
- n = vsnprintf(buffer, k, (char*)format, args);
- if(n < 0 || n > k ){
- n = k;
- }
- n = IOStream_write(stream, buffer, n);
- return n;
-}
-
-/** Print on a stream, like fprintf().
- *
- * @param stream to print to
- * @param format for the print (as fprintf())
- * @return result code from the print
- */
-int IOStream_print(IOStream *stream, const char *format, ...){
- va_list args;
- int result = -1;
-
- va_start(args, format);
- result = IOStream_vprint(stream, format, args);
- va_end(args);
- return result;
-}
+++ /dev/null
-#ifndef _XC_LINUX_SAVE_H_
-#define _XC_LINUX_SAVE_H_
-
-#include <stdarg.h>
-#include <stdint.h>
-#include <stddef.h>
-
-#ifdef __KERNEL__
-#include <linux/errno.h>
-#else
-#include <errno.h>
-#endif
-
-#include "allocate.h"
-
-/** End of input return value. */
-#define IOSTREAM_EOF -1
-
-/** An input/output abstraction.
- */
-typedef struct IOStream IOStream;
-
-/** Record of the functions to use for operations on an
- * IOStream implementation.
- */
-typedef struct IOMethods {
- /** Read function. Called with the user data, buffer to read into
- * and number of bytes to read. Must return number of bytes read
- * on success, less than zero on error.
- */
- int (*read)(IOStream *stream, void *buf, size_t n);
-
- /** Write function. Called with user data, buffer to write and
- * number of bytes to write. Must return number of bytes written on
- * success, less than zero otherwise.
- */
- int (*write)(IOStream *stream, const void *buf, size_t n);
-
- int (*flush)(IOStream *s);
-
- int (*error)(IOStream *s);
-
- int (*close)(IOStream *s);
-
- void (*free)(IOStream *s);
-
- void (*lock)(IOStream *s);
- void (*unlock)(IOStream *s);
-
-} IOMethods;
-
-/** Abstract i/o object.
- */
-struct IOStream {
- /** Methods to use to implement operations. */
- const IOMethods *methods;
- /** Private state for the implementation. */
- const void *data;
- /** Flag indicating whether the stream is closed. */
- int closed;
- /** Number of bytes written. */
- int written;
- /** Number of bytes read. */
- int read;
-};
-
-
-/** IOStream version of stdin. */
-extern IOStream *iostdin;
-
-/** IOStream version of stdout, */
-extern IOStream *iostdout;
-
-/** IOStream version of stderr. */
-extern IOStream *iostderr;
-
-extern int IOStream_print(IOStream *io, const char *format, ...);
-extern int IOStream_vprint(IOStream *io, const char *format, va_list args);
-
-/** Read from a stream.
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to read
- * @return if ok, number of bytes read, otherwise negative error code
- */
-static inline int IOStream_read(IOStream *stream, void *buf, size_t n){
- int result = 0;
- if(stream->closed) goto exit;
- if(!stream->methods || !stream->methods->read){
- result = -EINVAL;
- goto exit;
- }
- result = stream->methods->read(stream, buf, n);
- if(result > 0){
- stream->read += result;
- }
- exit:
- return result;
-}
-
-/** Write to a stream.
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to write
- * @return if ok, number of bytes read, otherwise negative error code
- */
-static inline int IOStream_write(IOStream *stream, const void *buf, size_t n){
- int result = 0;
- if(stream->closed) goto exit;
- if(!stream->methods || !stream->methods->write){
- result = -EINVAL;
- goto exit;
- }
- result = stream->methods->write(stream, buf, n);
- if(result > 0){
- stream->written += result;
- }
- exit:
- return result;
-}
-
-/** Flush the stream.
- *
- * @param stream stream
- * @return 0 on success, IOSTREAM_EOF otherwise
- */
-static inline int IOStream_flush(IOStream *stream){
- int result = 0;
- if(stream->closed){
- result = IOSTREAM_EOF;
- } else if(stream->methods->flush){
- result = stream->methods->flush(stream);
- if(result < 0) result = IOSTREAM_EOF;
- }
- return result;
-}
-
-/** Check whether the stream has an error.
- *
- * @param stream to check
- * @return 1 for error, 0 otherwise
- */
-static inline int IOStream_error(IOStream *stream){
- int err = 0;
- if(stream->methods && stream->methods->error){
- err = stream->methods->error(stream);
- }
- return err;
-}
-
-/** Close the stream.
- *
- * @param stream to close
- * @return 1 for error, 0 otherwise
- */
-static inline int IOStream_close(IOStream *stream){
- int err = 1;
- if(stream->methods && stream->methods->close){
- err = stream->methods->close(stream);
- }
- return err;
-}
-
-/** Test if the stream has been closed.
- *
- * @param stream to check
- * @return 1 if closed, 0 otherwise
- */
-static inline int IOStream_is_closed(IOStream *stream){
- return stream->closed;
-}
-
-/** Free the memory used by the stream.
- *
- * @param stream to free
- */
-static inline void IOStream_free(IOStream *stream){
- if(stream->methods && stream->methods->free){
- stream->methods->free(stream);
- }
- *stream = (IOStream){};
- deallocate(stream);
-}
-
-
-/** Print a character to a stream, like fputc().
- *
- * @param stream to print to
- * @param c character to print
- * @return result code from the print
- */
-static inline int IOStream_putc(IOStream *stream, int c){
- int err;
- unsigned char b = (unsigned char)c;
- err = IOStream_write(stream, &b, 1);
- if(err < 1){
- err = IOSTREAM_EOF;
- } else {
- err = b;
- }
- return err;
-}
-
-/** Read from a stream, like fgetc().
- *
- * @param stream to read from
- * @return IOSTREAM_EOF on error, character read otherwise
- */
-static inline int IOStream_getc(IOStream *stream){
- int err, rc;
- unsigned char b;
-
- err = IOStream_read(stream, &b, 1);
- if(err < 1){
- rc = IOSTREAM_EOF;
- } else {
- rc = b;
- }
- return rc;
-}
-
-/** Get number of bytes read.
- *
- * @param stream to get from
- * @return number of bytes read
- */
-static inline int IOStream_get_read(IOStream *stream){
- return stream->read;
-}
-
-/** Get number of bytes written.
- *
- * @param stream to get from
- * @return number of bytes written
- */
-static inline int IOStream_get_written(IOStream *stream){
- return stream->written;
-}
-
-
-#endif /* ! _XC_LINUX_SAVE_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * An IOStream implementation using printk() for output.
- * Input is not implemented.
- */
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-
-#include "kernel_stream.h"
-#include "allocate.h"
-
-/** Number of characters in the output buffer.
- * The kernel uses 1024 for printk, so that should suffice.
- */
-#define BUF_N 1024
-
-/** State for a kernel stream. */
-typedef struct KernelData {
- /** Stream lock. We need a lock to serialize access to the stream. */
- spinlock_t lock;
- /** Saved flags for locking. */
- unsigned long flags;
- /** Size of the output buffer. */
- int buf_n;
- /** Output buffer. */
- char buf[BUF_N];
-} KernelData;
-
-static int kernel_write(IOStream *s, const char *msg, int n);
-static void kernel_free(IOStream *s);
-static void kernel_stream_lock(IOStream *s);
-static void kernel_stream_unlock(IOStream *s);
-
-/** Methods for a kernel stream. Output only. */
-static const IOMethods kernel_methods = {
- write: kernel_write,
- free: kernel_free,
- lock: kernel_stream_lock,
- unlock: kernel_stream_unlock,
-};
-
-/** Shared state for kernel streams.
- * All implementations write using printk, so we can use
- * shared state and avoid allocating it.
- */
-static const KernelData kernel_data = {
- lock: SPIN_LOCK_UNLOCKED,
- flags: 0,
- buf_n: BUF_N,
-};
-
-/** Stream for kernel printk. */
-static IOStream iokernel = {
- methods: &kernel_methods,
- data: &kernel_data,
-};
-
-/** Stream for kernel printk. */
-IOStream *iostdout = &iokernel;
-
-/** Stream for kernel printk. */
-IOStream *iostdin = &iokernel;
-
-/** Stream for kernel printk. */
-IOStream *iostderr = &iokernel;
-
-/** Get an output-only stream implementation using
- * printk(). The stream uses static storage, and must not be freed.
- *
- * @return kernel stream
- */
-IOStream get_stream_kernel(void){
- return iokernel;
-}
-
-/** Obtain the lock on the stream state.
- *
- * @param kdata stream state
- */
-static inline void KernelData_lock(KernelData *kdata){
- spin_lock_irqsave(&kdata->lock, kdata->flags);
-}
-
-/** Release the lock on the stream state.
- *
- * @param kdata stream state
- */
-static inline void KernelData_unlock(KernelData *kdata){
- spin_unlock_irqrestore(&kdata->lock, kdata->flags);
-}
-
-/** Get the stream state.
- *
- * @param s kernel stream
- * @return stream state
- */
-static inline KernelData *get_kernel_data(IOStream *s){
- return (KernelData*)s->data;
-}
-
-/** Obtain the lock on the stream state.
- *
- * @param s stream
- */
-void kernel_stream_lock(IOStream *s){
- KernelData_lock(get_kernel_data(s));
-}
-
-/** Release the lock on the stream state.
- *
- * @param s stream
- */
-void kernel_stream_unlock(IOStream *s){
- KernelData_unlock(get_kernel_data(s));
-}
-
-/** Write to a kernel stream.
- *
- * @param stream kernel stream
- * @param format print format
- * @param args print arguments
- * @return result of the print
- */
-static int kernel_write(IOStream *stream, const char *buf, int n){
- KernelData *kdata = get_kernel_data(stream);
- int k;
- k = kdata->buf_n - 1;
- if(n < k) k = n;
- memcpy(kdata->buf, buf, k);
- kdata->buf[k] = '\0'
- printk(kdata->buf);
- return k;
-}
-
-/** Free a kernel stream.
- * Frees the internal state of the stream.
- * Do not call this unless the stream was dynamically allocated.
- * Do not call this on a stream returned from get_stream_kernel().
- *
- * @param io stream to free
- */
-static void kernel_free(IOStream *io){
- KernelData *kdata;
- if(io == &iokernel) return;
- kdata = get_kernel_data(io);
- zero(kdata, sizeof(*kdata));
- deallocate(kdata);
-}
-#endif /* __KERNEL__ */
-
-
-
-
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XEN_LIB_KERNEL_STREAM_H_
-#define _XEN_LIB_KERNEL_STREAM_H_
-
-#ifdef __KERNEL__
-#include "iostream.h"
-
-extern IOStream get_stream_kernel(void);
-#define get_stream_stdout get_stream_kernel
-
-#endif /* __KERNEL__ */
-#endif /* !_XEN_LIB_KERNEL_STREAM_H_ */
+++ /dev/null
-/*
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library is
- * distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * Lexical analysis.
- */
-
-#include "sys_string.h"
-#include "lexis.h"
-#include <errno.h>
-
-/** Check if a value lies in a (closed) range.
- *
- * @param x value to test
- * @param lo low end of the range
- * @param hi high end of the range
- * @return 1 if x is in the interval [lo, hi], 0 otherwise
- */
-inline static int in_range(int x, int lo, int hi){
- return (lo <= x) && (x <= hi);
-}
-
-/** Determine if a string is an (unsigned) decimal number.
- *
- * @param s pointer to characters to test
- * @param n length of string
- * @return 1 if s is a decimal number, 0 otherwise.
- */
-int is_decimal_number(const char *s, int n){
- int i;
- if(n <= 0)return 0;
- for(i = 0; i < n; i++){
- if(!in_decimal_digit_class(s[i])) return 0;
- }
- return 1;
-}
-
-/** Determine if a string is a hex number.
- * Hex numbers are 0, or start with 0x or 0X followed
- * by a non-zero number of hex digits (0-9,a-f,A-F).
- *
- * @param s pointer to characters to test
- * @param n length of string
- * @return 1 if s is a hex number, 0 otherwise.
- */
-int is_hex_number(const char *s, int n){
- int i;
- if(n <= 0) return 0;
- if(n == 1){
- return s[0]=='0';
- }
- if(n <= 3) return 0;
- if(s[0] != '0' || (s[1] != 'x' && s[1] != 'X')) return 0;
- for(i = 2; i < n; i++){
- if(!in_hex_digit_class(s[i])) return 0;
- }
- return 1;
-}
-
-/** Test if a string matches a keyword.
- * The comparison is case-insensitive.
- * The comparison fails if either argument is null.
- *
- * @param s string
- * @param k keyword
- * @return 1 if they match, 0 otherwise
- */
-int is_keyword(const char *s, const char *k){
- return s && k && !strcasecmp(s, k);
-}
-
-/** Test if a string matches a character.
- *
- * @param s string
- * @param c character (non-null)
- * @return 1 if s contains exactly c, 0 otherwise
- */
-int is_keychar(const char *s, char c){
- return c && (s[0] == c) && !s[1];
-}
+++ /dev/null
-/*
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library is
- * distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _SP_LEXIS_H_
-#define _SP_LEXIS_H_
-
-#include "sys_string.h"
-#include "sys_ctype.h"
-
-/** @file
- * Lexical analysis.
- */
-
-/** Class of characters treated as space. */
-#define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 })
-
-/** Class of separator characters. */
-#define sep_class "{}()<>[]@!;"
-
-#define comment_class "#"
-
-/** Determine if a character is in a given class.
- *
- * @param c character to test
- * @param s null-terminated string of characters in the class
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_class(int c, const char *s){
- return s && (strchr(s, c) != 0);
-}
-
-/** Determine if a character is in the space class.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_space_class(int c){
- return in_class(c, space_class);
-}
-
-static inline int in_comment_class(int c){
- return in_class(c, comment_class);
-}
-
-/** Determine if a character is in the separator class.
- * Separator characters terminate tokens, and do not need space
- * to separate them.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_sep_class(int c){
- return in_class(c, sep_class);
-}
-
-/** Determine if a character is in the alpha class.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_alpha_class(int c){
- return isalpha(c);
-}
-
-/** Determine if a character is in the octal digit class.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_octal_digit_class(int c){
- return '0' <= c && c <= '7';
-}
-
-/** Determine if a character is in the decimal digit class.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_decimal_digit_class(int c){
- return isdigit(c);
-}
-
-/** Determine if a character is in the hex digit class.
- *
- * @param c character to test
- * @return 1 if c is in the class, 0 otherwise.
- */
-static inline int in_hex_digit_class(int c){
- return isdigit(c) || in_class(c, "abcdefABCDEF");
-}
-
-
-static inline int in_string_quote_class(int c){
- return in_class(c, "'\"");
-}
-
-static inline int in_printable_class(int c){
- return ('A' <= c && c <= 'Z')
- || ('a' <= c && c <= 'z')
- || ('0' <= c && c <= '9')
- || in_class(c, "!$%&*+,-./:;<=>?@^_`{|}~");
-}
-
-extern int is_decimal_number(const char *s, int n);
-extern int is_hex_number(const char *s, int n);
-extern int is_keyword(const char *s, const char *k);
-extern int is_keychar(const char *s, char c);
-
-#endif /* !_SP_LEXIS_H_ */
+++ /dev/null
-/* $Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */
-#define __FILE_ID_INFO "$Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $"
-#include <what.h>
-static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO;
-/*
- * Copyright (C) 2003 Hewlett-Packard Company.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * An IOStream implementation using LZI to provide compression and decompression.
- * This is designed to provide compression without output latency.
- * Flushing an LZI stream flushes all pending data to the underlying stream.
- * This is essential for stream-based (e.g. networked) applications.
- *
- * A compressed data stream is a sequence of blocks.
- * Each block is the block size followed by the compressed data.
- * The last block has size zero.
- * Sizes are 4-byte unsigned in network order.
- *
- * This format allows compressed data to be read from a stream without reading
- * past the logical end of compressed data.
- *
- * @author Mike Wray <mike.wray@hpl.hp.com>
- */
-#ifndef __KERNEL__
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-
-#include "zlib.h"
-
-#include "allocate.h"
-#include "lzi_stream.h"
-#include "file_stream.h"
-#include "marshal.h"
-
-#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZI>%s" fmt, __FUNCTION__, ##args)
-#define wprintf(fmt, args...) fprintf(stderr, "[WARN] LZI>%s" fmt, __FUNCTION__, ##args)
-#define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZI>%s" fmt, __FUNCTION__, ##args)
-#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZI>%s" fmt, __FUNCTION__, ##args)
-
-static int lzi_read(IOStream *s, void *buf, size_t size, size_t count);
-static int lzi_write(IOStream *s, const void *buf, size_t size, size_t count);
-static int lzi_print(IOStream *s, const char *msg, va_list args);
-static int lzi_getc(IOStream *s);
-static int lzi_error(IOStream *s);
-static int lzi_close(IOStream *s);
-static void lzi_free(IOStream *s);
-static int lzi_flush(IOStream *s);
-
-enum {
- LZI_WRITE = 1,
- LZI_READ = 2,
-};
-
-/** Methods used by a gzFile* IOStream. */
-static const IOMethods lzi_methods = {
- read: lzi_read,
- write: lzi_write,
- print: lzi_print,
- getc: lzi_getc,
- error: lzi_error,
- close: lzi_close,
- free: lzi_free,
- flush: lzi_flush,
-};
-
-#define BUFFER_SIZE (512 * 1024)
-
-typedef struct LZIState {
- z_stream zstream;
- void *inbuf;
- uint32_t inbuf_size;
- void *outbuf;
- uint32_t outbuf_size;
- /** Underlying stream for I/O. */
- IOStream *io;
- /** Flags. */
- int flags;
- /** Error indicator. */
- int error;
- int eof;
- int plain_bytes;
- int comp_bytes;
- int zstream_initialized;
- int flushed;
-} LZIState;
-
-static inline int LZIState_writeable(LZIState *s){
- return (s->flags & LZI_WRITE) != 0;
-}
-
-static inline int LZIState_readable(LZIState *s){
- return (s->flags & LZI_READ) != 0;
-}
-
-void LZIState_free(LZIState *z){
- if(!z) return;
- if(z->zstream_initialized){
- if(LZIState_writeable(z)){
- deflateEnd(&z->zstream);
- } else if(LZIState_readable(z)){
- inflateEnd(&z->zstream);
- }
- }
- deallocate(z->inbuf);
- deallocate(z->outbuf);
- deallocate(z);
-}
-
-static int mode_flags(const char *mode, int *flags){
- int err = 0;
- int r=0, w=0;
- if(!mode){
- err = -EINVAL;
- goto exit;
- }
- for(; *mode; mode++){
- if(*mode == 'w') w = 1;
- if(*mode == 'r') r = 1;
- }
- if(r + w != 1){
- err = -EINVAL;
- goto exit;
- }
- if(r) *flags |= LZI_READ;
- if(w) *flags |= LZI_WRITE;
- exit:
- return err;
-}
-
-/** Get the stream state.
- *
- * @param s lzi stream
- * @return stream state.
- */
-static inline LZIState * lzi_state(IOStream *io){
- return io->data;
-}
-
-IOStream *lzi_stream_io(IOStream *io){
- LZIState *s = lzi_state(io);
- return s->io;
-}
-
-static inline void set_error(LZIState *s, int err){
- if(err < 0 && !s->error){
- s->error = err;
- }
-}
-
-static int zerror(LZIState *s, int err){
- if(err){
- //dprintf("> err=%d\n", err);
- if(err < 0) set_error(s, -EIO);
- }
- return s->error;
-}
-
-int lzi_stream_plain_bytes(IOStream *io){
- LZIState *s = lzi_state(io);
- return s->plain_bytes;
-}
-
-int lzi_stream_comp_bytes(IOStream *io){
- LZIState *s = lzi_state(io);
- return s->comp_bytes;
-}
-
-float lzi_stream_ratio(IOStream *io){
- LZIState *s = lzi_state(io);
- float ratio = 0.0;
- if(s->comp_bytes){
- ratio = ((float) s->comp_bytes)/((float) s->plain_bytes);
- }
- return ratio;
-}
-
-static int alloc(void **p, int n){
- *p = allocate(n);
- return (p ? 0 : -ENOMEM);
-}
-
-LZIState * LZIState_new(IOStream *io, int flags){
- int err = -ENOMEM;
- int zlevel = Z_BEST_SPEED; // Level 1 compression - fastest.
- int zstrategy = Z_DEFAULT_STRATEGY;
- int zwindow = MAX_WBITS;
- int zmemory = 8;
- LZIState *z = ALLOCATE(LZIState);
-
- //dprintf(">\n");
- if(!z) goto exit;
- z->io = io;
- z->flags = flags;
-
- if(LZIState_writeable(z)){
- z->outbuf_size = BUFFER_SIZE;
- /* windowBits is passed < 0 to suppress zlib header */
- err = deflateInit2(&z->zstream, zlevel, Z_DEFLATED, -zwindow, zmemory, zstrategy);
- if (err != Z_OK) goto exit;
- z->zstream_initialized = 1;
- err = alloc(&z->outbuf, z->outbuf_size);
- if(err) goto exit;
- z->zstream.next_out = z->outbuf;
- z->zstream.avail_out = z->outbuf_size;
- } else {
- z->inbuf_size = BUFFER_SIZE;
- err = alloc(&z->inbuf, z->inbuf_size);
- if(err) goto exit;
- ///z->zstream.next_in = z->inbuf;
-
- /* windowBits is passed < 0 to tell that there is no zlib header.
- * Note that in this case inflate *requires* an extra "dummy" byte
- * after the compressed stream in order to complete decompression and
- * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
- * present after the compressed stream.
- */
- err = inflateInit2(&z->zstream, -zwindow);
- if(err != Z_OK) goto exit;
- z->zstream_initialized = 1;
- }
-
- exit:
- if(err){
- LZIState_free(z);
- z = NULL;
- }
- //dprintf("< z=%p\n", z);
- return z;
-}
-
-int read_block(LZIState *s){
- int err = 0, k = 0;
- //dprintf(">\n");
- if(s->eof) goto exit;
- err = unmarshal_uint32(s->io, &k);
- if(err) goto exit;
- if(k > s->inbuf_size){
- err = -EINVAL;
- goto exit;
- }
- if(k){
- err = unmarshal_bytes(s->io, s->inbuf, k);
- if(err) goto exit;
- } else {
- s->eof = 1;
- }
- s->zstream.avail_in = k;
- s->zstream.next_in = s->inbuf;
- s->comp_bytes += 4;
- s->comp_bytes += k;
- exit:
- //dprintf("< err=%d\n", err);
- return err;
-}
-
-int write_block(LZIState *s){
- int err = 0;
- int k = ((char*)s->zstream.next_out) - ((char*)s->outbuf);
- int k2 = s->outbuf_size - s->zstream.avail_out;
- //dprintf("> k=%d k2=%d\n", k, k2);
- if(!k) goto exit;
- err = marshal_uint32(s->io, k);
- if(err) goto exit;
- err = marshal_bytes(s->io, s->outbuf, k);
- if(err) goto exit;
- s->zstream.next_out = s->outbuf;
- s->zstream.avail_out = s->outbuf_size;
- s->comp_bytes += 4;
- s->comp_bytes += k;
- exit:
- //dprintf("< err=%d\n", err);
- return err;
-}
-
-int write_terminator(LZIState *s){
- int err = 0;
- char c = 0;
- err = marshal_uint32(s->io, 1);
- if(err) goto exit;
- err = marshal_bytes(s->io, &c, 1);
- if(err) goto exit;
- err = marshal_uint32(s->io, 0);
- if(err) goto exit;
- s->comp_bytes += 9;
- exit:
- return err;
-}
-
-/** Write to the underlying stream using fwrite();
- *
- * @param io destination
- * @param buf data
- * @param size size of data elements
- * @param count number of data elements to write
- * @return number of data elements written
- */
-static int lzi_write(IOStream *io, const void *buf, size_t size, size_t count){
- int err = 0;
- int n = size * count;
- LZIState *s = lzi_state(io);
-
- //dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n);
- if(!LZIState_writeable(s)){
- err = -EINVAL;
- goto exit;
- }
- s->flushed = 0;
- s->zstream.next_in = (void*)buf;
- s->zstream.avail_in = n;
- while(s->zstream.avail_in){
- if(s->zstream.avail_out == 0){
- err = write_block(s);
- if(err) goto exit;
- }
- //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
- //dprintf("> 1 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out);
- err = zerror(s, deflate(&s->zstream, Z_NO_FLUSH));
- //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
- //dprintf("> 2 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out);
- if(err) goto exit;
- }
- err = n;
- s->plain_bytes += n;
- if(size != 1) err /= size;
- exit:
- //dprintf("< err=%d\n", err);
- return err;
-}
-
-
-/** Read from the underlying stream.
- *
- * @param io input
- * @param buf where to put input
- * @param size size of data elements
- * @param count number of data elements to read
- * @return number of data elements read
- */
-static int lzi_read(IOStream *io, void *buf, size_t size, size_t count){
- int err, zerr;
- int n = size * count;
- LZIState *s = lzi_state(io);
-
- //dprintf("> size=%d count=%d n=%d\n", size, count, n);
- if(!LZIState_readable(s)){
- err = -EINVAL;
- goto exit;
- }
- s->zstream.next_out = buf;
- s->zstream.avail_out = n;
- while(s->zstream.avail_out){
- if(s->zstream.avail_in == 0){
- err = read_block(s);
- }
- //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
- zerr = inflate(&s->zstream, Z_NO_FLUSH);
- //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
- if(zerr == Z_STREAM_END) break;
- //dprintf("> zerr=%d\n", zerr);
- err = zerror(s, zerr);
- if(err) goto exit;
- }
- err = n - s->zstream.avail_out;
- s->plain_bytes += err;
- if(size != 1) err /= size;
- exit:
- set_error(s, err);
- //dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Print to the underlying stream.
- * Returns 0 if the formatted output is too big for the internal buffer.
- *
- * @param io lzi stream
- * @param msg format to use
- * @param args arguments
- * @return result of the print
- */
-static int lzi_print(IOStream *io, const char *msg, va_list args){
- char buf[1024];
- int buf_n = sizeof(buf);
- int n;
- LZIState *s = lzi_state(io);
- if(!LZIState_writeable(s)){
- n = -EINVAL;
- goto exit;
- }
- n = vsnprintf(buf, buf_n, (char*)msg, args);
- if(n < 0) goto exit;
- if(n > buf_n){
- n = 0;
- } else {
- n = lzi_write(io, buf, 1, n);
- }
- exit:
- return n;
-}
-
-/** Read a character from the underlying stream
- *
- * @param io lzi stream
- * @return character read, IOSTREAM_EOF on end of file (or error)
- */
-static int lzi_getc(IOStream *io){
- int err;
- char c;
- err = lzi_read(io, &c, 1, 1);
- if(err < 1) c = EOF;
- err = (c==EOF ? IOSTREAM_EOF : c);
- return err;
-}
-
-static int flush_output(LZIState *s, int mode){
- int err = 0, zerr;
- int done = 0;
- int avail_out_old;
- int count = 10;
-
- //dprintf("> avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
- if(s->flushed == 1 + mode) goto exit;
- //s->zstream.avail_in = 0; /* should be zero already anyway */
- for(;;){
- // Write any available output.
- if(done || s->zstream.avail_out == 0){
- err = write_block(s);
- if(err) goto exit;
- if(done) break;
- }
- //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
- avail_out_old = s->zstream.avail_out;
- zerr = deflate(&s->zstream, mode);
- err = zerror(s, zerr);
- //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
- //dprintf("> deflate=%d\n", err);
- //done = (s->zstream.avail_out != 0);
- //done = (s->zstream.avail_in == 0) && (s->zstream.avail_out == avail_out_old);
- if(0 && mode == Z_FINISH){
- done = (zerr == Z_STREAM_END);
- } else {
- done = (s->zstream.avail_in == 0)
- //&& (s->zstream.avail_out == avail_out_old)
- && (s->zstream.avail_out != 0);
- }
- }
- s->flushed = 1 + mode;
- exit:
- //dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Flush any pending input to the underlying stream.
- *
- * @param s lzi stream
- * @return 0 on success, error code otherwise
- */
-static int lzi_flush(IOStream *io){
- int err = 0;
- LZIState *s = lzi_state(io);
- //dprintf(">\n");
- if(!LZIState_writeable(s)){
- err = -EINVAL;
- goto exit;
- }
- err = flush_output(s, Z_SYNC_FLUSH);
- if(err) goto exit;
- err = IOStream_flush(s->io);
- exit:
- set_error(s, err);
- //dprintf("< err=%d\n", err);
- return (err < 0 ? err : 0);
-}
-
-/** Check if a stream has an error.
- *
- * @param s lzi stream
- * @return code if has an error, 0 otherwise
- */
-static int lzi_error(IOStream *s){
- int err = 0;
- LZIState *state = lzi_state(s);
- err = state->error;
- if(err) goto exit;
- err = IOStream_error(state->io);
- exit:
- return err;
-}
-
-/** Close an lzi stream.
- *
- * @param s lzi stream to close
- * @return result of the close
- */
-static int lzi_close(IOStream *io){
- int err = 0;
- LZIState *s = lzi_state(io);
- if(LZIState_writeable(s)){
- err = flush_output(s, Z_FINISH);
- if(err) goto exit;
- err = write_terminator(s);
- if(err) goto exit;
- err = IOStream_flush(s->io);
- }
- exit:
- err = IOStream_close(s->io);
- set_error(s, err);
- return err;
-}
-
-/** Free an lzi stream.
- *
- * @param s lzi stream
- */
-static void lzi_free(IOStream *s){
- LZIState *state = lzi_state(s);
- IOStream_free(state->io);
- LZIState_free(state);
- s->data = NULL;
-}
-
-/** Create an lzi stream for an IOStream.
- *
- * @param io stream to wrap
- * @return new IOStream using f for i/o
- */
-IOStream *lzi_stream_new(IOStream *io, const char *mode){
- int err = -ENOMEM;
- int flags = 0;
- IOStream *zio = NULL;
- LZIState *state = NULL;
-
- zio = ALLOCATE(IOStream);
- if(!zio) goto exit;
- err = mode_flags(mode, &flags);
- if(err) goto exit;
- state = LZIState_new(io, flags);
- if(!state) goto exit;
- err = 0;
- zio->data = state;
- zio->methods = &lzi_methods;
- exit:
- if(err){
- if(state) LZIState_free(state);
- if(zio) deallocate(zio);
- zio = NULL;
- }
- return zio;
-}
-
-/** IOStream version of fdopen().
- *
- * @param fd file descriptor
- * @param flags giving the mode to open in (as for fdopen())
- * @return new stream for the open file, or NULL if failed
- */
-IOStream *lzi_stream_fdopen(int fd, const char *mode){
- int err = -ENOMEM;
- IOStream *io = NULL, *zio = NULL;
- io = file_stream_fdopen(fd, mode);
- if(!io) goto exit;
- zio = lzi_stream_new(io, mode);
- if(!io) goto exit;
- err = 0;
- exit:
- if(err){
- IOStream_free(io);
- IOStream_free(zio);
- zio = NULL;
- }
- return zio;
-}
-#endif
+++ /dev/null
-#/* $Id: lzi_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */
-/*
- * Copyright (C) 2003 Hewlett-Packard Company.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _SP_LZI_STREAM_H_
-#define _SP_LZI_STREAM_H_
-
-#ifndef __KERNEL__
-#include "iostream.h"
-
-extern IOStream *lzi_stream_new(IOStream *io, const char *mode);
-extern IOStream *lzi_stream_fopen(const char *file, const char *mode);
-extern IOStream *lzi_stream_fdopen(int fd, const char *mode);
-extern IOStream *lzi_stream_io(IOStream *zio);
-
-extern int lzi_stream_plain_bytes(IOStream *io);
-extern int lzi_stream_comp_bytes(IOStream *io);
-extern float lzi_stream_ratio(IOStream *io);
-
-#endif
-#endif /* !_SP_FILE_STREAM_H_ */
+++ /dev/null
-/* $Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */
-#define __FILE_ID_INFO "$Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $"
-#include <what.h>
-static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO;
-/*
- * Copyright (C) 2003 Hewlett-Packard Company.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * An IOStream implementation using LZO to provide compression and decompression.
- * This is designed to provide reasonable compression without output latency.
- * Flushing an LZO stream flushes all pending data to the underlying stream.
- * This is essential for stream-based (e.g. networked) applications.
- *
- * A compressed data stream is a sequence of blocks.
- * Each block except the last is the plain data size followed by the compressed data size
- * and the compressed data. The last block has plain data size zero and omits the rest.
- * Sizes are 4-byte unsigned in network order. If the compressed size is smaller than
- * the plain size the block data is compressed, otherwise it is plain (uncompressed).
- *
- * This format allows compressed data to be read from a stream without reading
- * past the logical end of compressed data.
- *
- * @author Mike Wray <mike.wray@hpl.hp.com>
- */
-#ifndef __KERNEL__
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-
-#include "lzo1x.h"
-
-#include "allocate.h"
-#include "lzo_stream.h"
-#include "file_stream.h"
-#include "marshal.h"
-
-#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZO>%s" fmt, __FUNCTION__, ##args)
-#define wprintf(fmt, args...) fprintf(stderr, "[WARN] LZO>%s" fmt, __FUNCTION__, ##args)
-#define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZO>%s" fmt, __FUNCTION__, ##args)
-#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZO>%s" fmt, __FUNCTION__, ##args)
-
-static int lzo_read(IOStream *s, void *buf, size_t size, size_t count);
-static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count);
-static int lzo_print(IOStream *s, const char *msg, va_list args);
-static int lzo_getc(IOStream *s);
-static int lzo_error(IOStream *s);
-static int lzo_close(IOStream *s);
-static void lzo_free(IOStream *s);
-static int lzo_flush(IOStream *s);
-
-enum {
- LZO_WRITE = 1,
- LZO_READ = 2,
-};
-
-/** Methods used by a gzFile* IOStream. */
-static const IOMethods lzo_methods = {
- read: lzo_read,
- write: lzo_write,
- print: lzo_print,
- getc: lzo_getc,
- error: lzo_error,
- close: lzo_close,
- free: lzo_free,
- flush: lzo_flush,
-};
-
-//#define PLAIN_SIZE (64 * 1024)
-//#define PLAIN_SIZE (128 * 1024)
-#define PLAIN_SIZE (512 * 1024)
-
-//#define NOCOMPRESS
-
-typedef struct LZOState {
- /** Flags. */
- int flags;
- /** Error indicator. */
- int error;
- /** Underlying stream for I/O. */
- IOStream *io;
- /** Working memory (only needed for compression, not decompression). */
- lzo_byte *memory;
- /** Buffer for plain (uncompressed) data. */
- lzo_byte *plain;
- /** Size of the plain buffer. */
- lzo_uint plain_size;
- /** Pointer into the plain buffer. */
- lzo_byte *plain_ptr;
- /** Number of bytes of plain data available. */
- lzo_uint plain_n;
- /** Buffer for compressed data. */
- lzo_byte *comp;
- /** Size of the compressed buffer. */
- lzo_uint comp_size;
-
- int plain_bytes;
- int comp_bytes;
-} LZOState;
-
-void LZOState_free(LZOState *z){
- if(!z) return;
- deallocate(z->memory);
- deallocate(z->plain);
- deallocate(z->comp);
- deallocate(z);
-}
-
-/** Maximum size of compressed data for the given plain data size.
- *
- * @param plain_size size of plain data
- * @return maximum size of compressed data
- */
-static int comp_size(int plain_size){
- return plain_size + (plain_size / 64) + 16 + 3;
-}
-
-static int mode_flags(const char *mode, int *flags){
- int err = 0;
- int r=0, w=0;
- if(!mode){
- err = -EINVAL;
- goto exit;
- }
- for(; *mode; mode++){
- if(*mode == 'w') w = 1;
- if(*mode == 'r') r = 1;
- }
- if(r + w != 1){
- err = -EINVAL;
- goto exit;
- }
- if(r) *flags |= LZO_READ;
- if(w) *flags |= LZO_WRITE;
- exit:
- return err;
-}
-
-/** Get the stream state.
- *
- * @param s lzo stream
- * @return stream state.
- */
-static inline LZOState * lzo_state(IOStream *s){
- return s->data;
-}
-
-IOStream *lzo_stream_io(IOStream *s){
- LZOState *state = lzo_state(s);
- return state->io;
-}
-
-static inline void set_error(LZOState *state, int err){
- if(err < 0 && !state->error){
- state->error = err;
- }
-}
-
-int lzo_stream_plain_bytes(IOStream *s){
- LZOState *state = lzo_state(s);
- return state->plain_bytes;
-}
-
-int lzo_stream_comp_bytes(IOStream *s){
- LZOState *state = lzo_state(s);
- return state->comp_bytes;
-}
-
-float lzo_stream_ratio(IOStream *s){
- LZOState *state = lzo_state(s);
- float ratio = 0.0;
- if(state->comp_bytes){
- ratio = ((float) state->comp_bytes)/((float) state->plain_bytes);
- }
- return ratio;
-}
-
-static inline int LZOState_writeable(LZOState *state){
- return (state->flags & LZO_WRITE) != 0;
-}
-
-static inline int LZOState_readable(LZOState *state){
- return (state->flags & LZO_READ) != 0;
-}
-
-LZOState * LZOState_new(IOStream *io, int flags){
- int err = -ENOMEM;
- LZOState *z = ALLOCATE(LZOState);
- //dprintf(">\n");
- if(!z) goto exit;
- z->io = io;
- z->flags = flags;
- if(LZOState_writeable(z)){
- z->memory = allocate(LZO1X_1_MEM_COMPRESS);
- if(!z->memory) goto exit;
- }
- z->plain_size = PLAIN_SIZE;
- z->plain = allocate(z->plain_size);
- if(!z->plain) goto exit;
- z->plain_ptr = z->plain;
- z->comp_size = comp_size(z->plain_size);
- z->comp = allocate(z->comp_size);
- if(!z->comp) goto exit;
- err = 0;
- exit:
- if(err){
- LZOState_free(z);
- z = NULL;
- }
- //dprintf("< z=%p\n", z);
- return z;
-}
-
-static int lzo_compress(LZOState *state){
- int err = 0;
- int k, comp_n;
- //dprintf(">\n");
- //dprintf(">plain=%p plain_n=%d comp=%p memory=%p\n", state->plain, state->plain_n, state->comp, state->memory);
- // Compress the plain buffer.
- err = lzo1x_1_compress(state->plain, state->plain_n,
- state->comp, &comp_n,
- state->memory);
- //dprintf("> err=%d plain_n=%d comp_n=%d\n", err, state->plain_n, comp_n);
- // Write plain size, compressed size.
- err = marshal_uint32(state->io, state->plain_n);
- if(err) goto exit;
- err = marshal_uint32(state->io, comp_n);
- if(err) goto exit;
- //dprintf("> write data...\n");
- // Write the smaller of the compressed and plain data.
- if(state->plain_n < comp_n){
- k = state->plain_n;
- err = marshal_bytes(state->io, state->plain, state->plain_n);
- } else {
- k = comp_n;
- err = marshal_bytes(state->io, state->comp, comp_n);
- }
- if(err) goto exit;
- // Total output bytes.
- k+= 8;
- //dprintf("> wrote %d bytes\n", k);
- state->plain_bytes += state->plain_n;
- state->comp_bytes += k;
- //dprintf("> plain=%d, comp=%d, ratio=%3.2f\n",
- // state->plain_bytes, state->comp_bytes,
- // ((float)state->comp_bytes)/((float)state->plain_bytes));
- // Reset the plain buffer.
- state->plain_ptr = state->plain;
- state->plain_n = 0;
- err = k;
- exit:
- //dprintf("< err=%d\n", err);
- return err;
-}
-
-static int lzo_decompress(LZOState *state){
- int plain_n, comp_n;
- int err, k;
- //dprintf(">\n");
- err = unmarshal_uint32(state->io, &plain_n);
- //dprintf("> err=%d plain_n=%d\n", err, plain_n);
- if(err) goto exit;
- state->comp_bytes += 4;
- if(plain_n == 0) goto exit;
- err = unmarshal_uint32(state->io, &comp_n);
- //dprintf("> err=%d comp_n=%d\n", err, comp_n);
- if(err) goto exit;
- state->comp_bytes += 4;
- if(plain_n > state->plain_size){
- err = -EINVAL;
- goto exit;
- }
- if(comp_n > plain_n){
- //dprintf("> reading plain data %d...\n", plain_n);
- k = plain_n;
- err = unmarshal_bytes(state->io, state->plain, plain_n);
- state->plain_n = plain_n;
- } else {
- //dprintf("> reading comp data %d...\n", comp_n);
- k = comp_n;
- err = unmarshal_bytes(state->io, state->comp, comp_n);
- //dprintf("> decompress comp_n=%d\n", comp_n);
- err = lzo1x_decompress(state->comp, comp_n,
- state->plain, &state->plain_n,
- state->memory);
- //dprintf("> err=%d plain=%d state->plain_n=%d\n", err, plain_n, state->plain_n);
- if(err != LZO_E_OK || state->plain_n != plain_n){
- // Bad. Corrupted input.
- err = -EINVAL;
- eprintf("> Corrupted!\n");
- goto exit;
- }
- }
- state->comp_bytes += k;
- state->plain_bytes += state->plain_n;
- state->plain_ptr = state->plain;
- err = k;
- exit:
- //dprintf("< err=%d\n", err);
- return err;
-}
-
-/** Write to the underlying stream using fwrite();
- *
- * @param stream destination
- * @param buf data
- * @param size size of data elements
- * @param count number of data elements to write
- * @return number of data elements written
- */
-static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count){
- int err = 0;
- int n = size * count; // Total number of bytes to write.
- int chunk; // Size of chunk to write.
- int remaining; // Number of bytes remaining to write.
- int space; // Amount of space left in plain buffer.
- LZOState *state = lzo_state(s);
-#ifdef NOCOMPRESS
- //dprintf("> buf=%p size=%d count=%d\n", buf, size, count);
- err = IOStream_write(state->io, buf, size, count);
- //dprintf("< err=%d\n", err);
-#else
- //dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n);
- remaining = n;
- space = state->plain_size - state->plain_n;
- //dprintf("> plain=%p plain_ptr=%p plain_n=%d space=%d\n",
- // state->plain, state->plain_ptr, state->plain_n, space);
- while(remaining){
- chunk = remaining;
- if(chunk > space) chunk = space;
- //dprintf("> memcpy %p %p %d\n", state->plain_ptr, buf, chunk);
- memcpy(state->plain_ptr, buf, chunk);
- remaining -= chunk;
- space -= chunk;
- state->plain_ptr += chunk;
- state->plain_n += chunk;
- if(space == 0){
- // Input buffer is full. Compress and write it.
- err = lzo_compress(state);
- if(err < 0) goto exit;
- space = state->plain_size - state->plain_n;
- }
- }
- err = (size > 1 ? n / size : n);
- exit:
- set_error(state, err);
-#endif
- return err;
-}
-
-
-/** Read from the underlying stream.
- *
- * @param stream input
- * @param buf where to put input
- * @param size size of data elements
- * @param count number of data elements to read
- * @return number of data elements read
- */
-static int lzo_read(IOStream *s, void *buf, size_t size, size_t count){
- int err = 0;
- int k = 0; // Number of (plain) bytes read.
- int remaining = size * count; // Number of bytes remaining to read.
- int chunk; // Size of chunk to read.
- LZOState *state = lzo_state(s);
-#ifdef NOCOMPRESS
- //dprintf("> buf=%p size=%d count=%d\n", buf, size, count);
- err = IOStream_read(state->io, buf, size, count);
- //dprintf("< err=%d\n", err);
-#else
- if(!(state->flags & LZO_READ)){
- err = -EINVAL;
- goto exit;
- }
- while(remaining){
- if(state->plain_n == 0){
- // No more plain input, decompress some more.
- err = lzo_decompress(state);
- if(err < 0) goto exit;
- // Stop reading if there is no more input.
- if(err == 0 || state->plain_n == 0) break;
- }
- chunk = remaining;
- if(chunk > state->plain_n) chunk = state->plain_n;
- memcpy(buf, state->plain_ptr, chunk);
- k += chunk;
- buf += chunk;
- state->plain_ptr += chunk;
- state->plain_n -= chunk;
- remaining -= chunk;
- }
- err = k;
- exit:
- set_error(state, err);
-#endif
- return err;
-}
-
-/** Print to the underlying stream.
- * Returns 0 if the formatted output is too big for the internal buffer.
- *
- * @param s lzo stream
- * @param msg format to use
- * @param args arguments
- * @return result of the print
- */
-static int lzo_print(IOStream *s, const char *msg, va_list args){
- char buf[1024];
- int buf_n = sizeof(buf);
- int n;
- LZOState *state = lzo_state(s);
- if(!LZOState_writeable(state)){
- n = -EINVAL;
- goto exit;
- }
- n = vsnprintf(buf, buf_n, (char*)msg, args);
- if(n < 0) goto exit;
- if(n > buf_n){
- n = 0;
- } else {
- n = lzo_write(s, buf, 1, n);
- }
- exit:
- return n;
-}
-
-/** Read a character from the underlying stream
- *
- * @param s lzo stream
- * @return character read, IOSTREAM_EOF on end of file (or error)
- */
-static int lzo_getc(IOStream *s){
- int err;
- char c;
- err = lzo_read(s, &c, 1, 1);
- if(err < 1) c = EOF;
- err = (c==EOF ? IOSTREAM_EOF : c);
- return err;
-}
-
-/** Flush any pending input to the underlying stream.
- *
- * @param s lzo stream
- * @return 0 on success, error code otherwise
- */
-static int lzo_flush(IOStream *s){
- int err = 0;
- LZOState *state = lzo_state(s);
- //dprintf(">\n");
-#ifdef NOCOMPRESS
- err = IOStream_flush(state->io);
-#else
- if(!LZOState_writeable(state)){
- err = -EINVAL;
- goto exit;
- }
- if(state->plain_n){
- err = lzo_compress(state);
- if(err < 0) goto exit;
- }
- err = IOStream_flush(state->io);
- exit:
- set_error(state, err);
-#endif
- //dprintf("< err=%d\n", err);
- return (err < 0 ? err : 0);
-}
-
-/** Check if a stream has an error.
- *
- * @param s lzo stream
- * @return code if has an error, 0 otherwise
- */
-static int lzo_error(IOStream *s){
- int err = 0;
- LZOState *state = lzo_state(s);
- err = state->error;
- if(err) goto exit;
- err = IOStream_error(state->io);
- exit:
- return err;
-}
-
-int lzo_stream_finish(IOStream *s){
- int err = 0;
- LZOState *state = lzo_state(s);
- if(!LZOState_writeable(state)){
- err = -EINVAL;
- goto exit;
- }
- err = lzo_flush(s);
- if(err < 0) goto exit;
- err = marshal_int32(state->io, 0);
- exit:
- return err;
-}
-
-/** Close an lzo stream.
- *
- * @param s lzo stream to close
- * @return result of the close
- */
-static int lzo_close(IOStream *s){
- int err = 0;
- LZOState *state = lzo_state(s);
-#ifdef NOCOMPRESS
- err = IOStream_close(state->io);
-#else
- if(LZOState_writeable(state)){
- err = lzo_stream_finish(s);
- }
- err = IOStream_close(state->io);
- set_error(state, err);
-#endif
- return err;
-}
-
-/** Free an lzo stream.
- *
- * @param s lzo stream
- */
-static void lzo_free(IOStream *s){
- LZOState *state = lzo_state(s);
- IOStream_free(state->io);
- LZOState_free(state);
- s->data = NULL;
-}
-
-/** Create an lzo stream for an IOStream.
- *
- * @param io stream to wrap
- * @return new IOStream using f for i/o
- */
-IOStream *lzo_stream_new(IOStream *io, const char *mode){
- int err = -ENOMEM;
- int flags = 0;
- IOStream *zio = NULL;
- LZOState *state = NULL;
-
- zio = ALLOCATE(IOStream);
- if(!zio) goto exit;
- err = mode_flags(mode, &flags);
- if(err) goto exit;
- state = LZOState_new(io, flags);
- if(!state) goto exit;
- err = 0;
- zio->data = state;
- zio->methods = &lzo_methods;
- exit:
- if(err){
- if(state) LZOState_free(state);
- if(zio) deallocate(zio);
- zio = NULL;
- }
- return zio;
-}
-
-/** IOStream version of fdopen().
- *
- * @param fd file descriptor
- * @param flags giving the mode to open in (as for fdopen())
- * @return new stream for the open file, or NULL if failed
- */
-IOStream *lzo_stream_fdopen(int fd, const char *mode){
- int err = -ENOMEM;
- IOStream *io = NULL, *zio = NULL;
- io = file_stream_fdopen(fd, mode);
- if(!io) goto exit;
- zio = lzo_stream_new(io, mode);
- if(!io) goto exit;
- err = 0;
- exit:
- if(err){
- IOStream_free(io);
- IOStream_free(zio);
- zio = NULL;
- }
- return zio;
-}
-#endif
+++ /dev/null
-#/* $Id: lzo_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */
-/*
- * Copyright (C) 2003 Hewlett-Packard Company.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _SP_LZO_STREAM_H_
-#define _SP_LZO_STREAM_H_
-
-#ifndef __KERNEL__
-#include "iostream.h"
-
-extern IOStream *lzo_stream_new(IOStream *io, const char *mode);
-extern IOStream *lzo_stream_fopen(const char *file, const char *mode);
-extern IOStream *lzo_stream_fdopen(int fd, const char *mode);
-extern IOStream *lzo_stream_io(IOStream *zio);
-
-extern int lzo_stream_plain_bytes(IOStream *io);
-extern int lzo_stream_comp_bytes(IOStream *io);
-extern float lzo_stream_ratio(IOStream *io);
-
-#endif
-#endif /* !_SP_FILE_STREAM_H_ */
+++ /dev/null
-#include <errno.h>
-#include "sys_net.h"
-#include "allocate.h"
-#include "marshal.h"
-
-#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
-#define wprintf(fmt, args...) IOStream_print(iostderr, "[WARN] %s" fmt, __FUNCTION__, ##args)
-#define iprintf(fmt, args...) IOStream_print(iostdout, "[INFO] %s" fmt, __FUNCTION__, ##args)
-#define eprintf(fmt, args...) IOStream_print(iostderr, "[ERROR] %s" fmt, __FUNCTION__, ##args)
-
-
-#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof((ary)[0]))
-
-/* Messages are coded as msgid followed by message fields.
- * Initial message on any channel is hello - so can check version
- * compatibility.
- *
- * char* -> uint16_t:n <n bytes>
- * ints/uints go as suitable number of bytes (e.g. uint16_t is 2 bytes).
- * optional fields go as '1' <val> or '0' (the 0/1 is 1 byte).
- * lists go as ('1' <elt>)* '0'
- */
-
-int marshal_flush(IOStream *io){
- int err = 0;
- err = IOStream_flush(io);
- return err;
-}
-
-int marshal_bytes(IOStream *io, void *s, uint32_t s_n){
- int err = 0;
- int n;
- n = IOStream_write(io, s, s_n);
- if(n < 0){
- err = n;
- } else if (n < s_n){
- wprintf("> Wanted %d, got %d\n", s_n, n);
- err = -EIO;
- }
- return err;
-}
-
-int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n){
- int err = 0;
- int n;
- //dprintf("> s_n=%d\n", s_n);
- n = IOStream_read(io, s, s_n);
- //dprintf("> n=%d\n", n);
- if(n < 0){
- err = n;
- } else if(n < s_n){
- wprintf("> Wanted %d, got %d\n", s_n, n);
- err = -EIO;
- }
- //dprintf("< err=%d\n", err);
- return err;
-}
-
-int marshal_uint8(IOStream *io, uint8_t x){
- return marshal_bytes(io, &x, sizeof(x));
-}
-
-int unmarshal_uint8(IOStream *io, uint8_t *x){
- return unmarshal_bytes(io, x, sizeof(*x));
-}
-
-int marshal_uint16(IOStream *io, uint16_t x){
- x = htons(x);
- return marshal_bytes(io, &x, sizeof(x));
-}
-
-int unmarshal_uint16(IOStream *io, uint16_t *x){
- int err = 0;
- err = unmarshal_bytes(io, x, sizeof(*x));
- *x = ntohs(*x);
- return err;
-}
-
-int marshal_int32(IOStream *io, int32_t x){
- int err = 0;
- //dprintf("> x=%d\n", x);
- x = htonl(x);
- err = marshal_bytes(io, &x, sizeof(x));
- //dprintf("< err=%d\n", err);
- return err;
-}
-
-int unmarshal_int32(IOStream *io, int32_t *x){
- int err = 0;
- //dprintf(">\n");
- err = unmarshal_bytes(io, x, sizeof(*x));
- *x = ntohl(*x);
- //dprintf("< err=%d x=%d\n", err, *x);
- return err;
-}
-
-int marshal_uint32(IOStream *io, uint32_t x){
- int err = 0;
- //dprintf("> x=%u\n", x);
- x = htonl(x);
- err = marshal_bytes(io, &x, sizeof(x));
- //dprintf("< err=%d\n", err);
- return err;
-}
-
-int unmarshal_uint32(IOStream *io, uint32_t *x){
- int err = 0;
- //dprintf(">\n");
- err = unmarshal_bytes(io, x, sizeof(*x));
- *x = ntohl(*x);
- //dprintf("< err=%d x=%u\n", err, *x);
- return err;
-}
-
-int marshal_uint64(IOStream *io, uint64_t x){
- int err;
- err = marshal_uint32(io, (uint32_t) ((x >> 32) & 0xffffffff));
- if(err) goto exit;
- err = marshal_uint32(io, (uint32_t) ( x & 0xffffffff));
- exit:
- return err;
-}
-
-int unmarshal_uint64(IOStream *io, uint64_t *x){
- int err = 0;
- uint32_t hi, lo;
- err = unmarshal_uint32(io, &hi);
- if(err) goto exit;
- err = unmarshal_uint32(io, &lo);
- *x = (((uint64_t) hi) << 32) | lo;
- exit:
- return err;
-}
-
-int marshal_net16(IOStream *io, net16_t x){
- return marshal_bytes(io, &x, sizeof(x));
-}
-
-int unmarshal_net16(IOStream *io, net16_t *x){
- int err = 0;
- err = unmarshal_bytes(io, x, sizeof(*x));
- return err;
-}
-
-int marshal_net32(IOStream *io, net32_t x){
- return marshal_bytes(io, &x, sizeof(x));
-}
-
-int unmarshal_net32(IOStream *io, net32_t *x){
- int err = 0;
- err = unmarshal_bytes(io, x, sizeof(*x));
- return err;
-}
-
-int marshal_string(IOStream *io, char *s, uint32_t s_n){
- int err;
- //dprintf("> s=%s\n", s);
- err = marshal_uint32(io, s_n);
- if(err) goto exit;
- err = marshal_bytes(io, s, s_n);
- exit:
- //dprintf("< err=%d\n", err);
- return err;
-}
-
-int unmarshal_string(IOStream *io, char *s, uint32_t s_n){
- int err = 0, val_n = 0;
- //dprintf(">\n");
- err = unmarshal_uint32(io, &val_n);
- if(err) goto exit;
- if(val_n >= s_n){
- err = -EINVAL;
- goto exit;
- }
- err = unmarshal_bytes(io, s, val_n);
- if(err) goto exit;
- s[val_n] = '\0';
- exit:
- //dprintf("< err=%d s=%s\n", err, s);
- return err;
-}
-
-int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n){
- int err = 0, val_n = 0;
- char *val = NULL;
- //dprintf(">\n");
- err = unmarshal_uint32(io, &val_n);
- if(err) goto exit;
- val = allocate(val_n + 1);
- if(!val){
- err = -ENOMEM;
- goto exit;
- }
- err = unmarshal_bytes(io, val, val_n);
- if(err) goto exit;
- val[val_n] = '\0';
- exit:
- if(err){
- if(val) deallocate(val);
- val = NULL;
- val_n = 0;
- }
- *s = val;
- if(s_n) *s_n = val_n;
- //dprintf("< err=%d s=%s\n", err, *s);
- return err;
-}
+++ /dev/null
-/* $Id: marshal.h,v 1.1 2003/10/17 15:48:43 mjw Exp $ */
-#ifndef _SP_MARSHAL_H_
-#define _SP_MARSHAL_H_
-
-#include "iostream.h"
-
-/** A 16-bit uint in network order, e.g. a port number. */
-typedef uint16_t net16_t;
-
-/** A 32-bit uint in network order, e.g. an IP address. */
-typedef uint32_t net32_t;
-
-extern int marshal_flush(IOStream *io);
-
-extern int marshal_bytes(IOStream *io, void *s, uint32_t s_n);
-extern int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n);
-
-extern int marshal_uint8(IOStream *io, uint8_t x);
-extern int unmarshal_uint8(IOStream *io, uint8_t *x);
-
-extern int marshal_uint16(IOStream *io, uint16_t x);
-extern int unmarshal_uint16(IOStream *io, uint16_t *x);
-
-extern int marshal_uint32(IOStream *io, uint32_t x);
-extern int unmarshal_uint32(IOStream *io, uint32_t *x);
-
-extern int marshal_int32(IOStream *io, int32_t x);
-extern int unmarshal_int32(IOStream *io, int32_t *x);
-
-extern int marshal_uint64(IOStream *io, uint64_t x);
-extern int unmarshal_uint64(IOStream *io, uint64_t *x);
-
-extern int marshal_net16(IOStream *io, net16_t x);
-extern int unmarshal_net16(IOStream *io, net16_t *x);
-
-extern int marshal_net32(IOStream *io, net32_t x);
-extern int unmarshal_net32(IOStream *io, net32_t *x);
-
-extern int marshal_string(IOStream *io, char *s, uint32_t s_n);
-extern int unmarshal_string(IOStream *io, char *s, uint32_t s_n);
-extern int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n);
-
-#endif /* ! _SP_MARSHAL_H_ */
+++ /dev/null
-/* $Id: socket_stream.c,v 1.9 2004/03/05 14:45:34 mjw Exp $ */
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * An IOStream implementation using sockets.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include "allocate.h"
-#include "socket_stream.h"
-
-#define MODULE_NAME "sock"
-#define DEBUG 0
-//#undef DEBUG
-#include "debug.h"
-
-static int socket_read(IOStream *s, void *buf, size_t n);
-static int socket_write(IOStream *s, const void *buf, size_t n);
-static int socket_error(IOStream *s);
-static int socket_close(IOStream *s);
-static void socket_free(IOStream *s);
-static int socket_flush(IOStream *s);
-
-/** Methods used by a socket IOStream. */
-static const IOMethods socket_methods = {
- read: socket_read,
- write: socket_write,
- error: socket_error,
- close: socket_close,
- free: socket_free,
- flush: socket_flush,
-};
-
-/** Get the socket data.
- *
- * @param io socket stream
- * @return data
- */
-static inline SocketData * socket_data(IOStream *io){
- return (SocketData *)io->data;
-}
-
-/** Test if a stream is a socket stream.
- *
- * @param io stream
- * @return 0 if a socket stream, -EINVAL if not
- */
-int socket_stream_check(IOStream *io){
- return (io && io->methods == &socket_methods ? 0 : -EINVAL);
-}
-
-/** Get the data for a socket stream.
- *
- * @param io stream
- * @param data return value for the data
- * @return 0 if a socket stream, -EINVAL if not
- */
-int socket_stream_data(IOStream *io, SocketData **data){
- int err = socket_stream_check(io);
- if(err){
- *data = NULL;
- } else {
- *data = socket_data(io);
- }
- return err;
-}
-
-/** Set the destination address for a socket stream.
- *
- * @param io stream
- * @param addr address
- * @return 0 if a socket stream, -EINVAL if not
- */
-int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr){
- int err = 0;
- SocketData *data = NULL;
- err = socket_stream_data(io, &data);
- if(!err){
- data->daddr = *addr;
- }
- return err;
-}
-
-/** Set the send flags for a socket stream.
- *
- * @param io stream
- * @param flags flags
- * @return 0 if a socket stream, -EINVAL if not
- */
-int socket_stream_set_flags(IOStream *io, int flags){
- int err = 0;
- SocketData *data = NULL;
- err = socket_stream_data(io, &data);
- if(!err){
- data->flags = flags;
- }
- return err;
-}
-
-/** Write to the underlying socket using sendto.
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to write
- * @return number of bytes written
- */
-static int socket_write(IOStream *s, const void *buf, size_t n){
- SocketData *data = socket_data(s);
- struct sockaddr *daddr = (struct sockaddr *)&data->daddr;
- socklen_t daddr_n = sizeof(data->daddr);
- int k;
- dprintf("> sock=%d addr=%s:%d n=%d\n",
- data->fd, inet_ntoa(data->daddr.sin_addr), ntohs(data->daddr.sin_port), n);
- if(0){
- struct sockaddr_in self = {};
- socklen_t self_n;
- getsockname(data->fd, (struct sockaddr *)&self, &self_n);
- dprintf("> sockname sock=%d %s:%d\n",
- data->fd, inet_ntoa(self.sin_addr), ntohs(self.sin_port));
- }
- k = sendto(data->fd, buf, n, data->flags, daddr, daddr_n);
- dprintf("> sendto=%d\n", k);
- return k;
-}
-
-/** Read from the underlying stream using recv();
- *
- * @param stream input
- * @param buf where to put input
- * @param n number of bytes to read
- * @return number of bytes read
- */
-static int socket_read(IOStream *s, void *buf, size_t n){
- SocketData *data = socket_data(s);
- int k;
- struct sockaddr *saddr = (struct sockaddr *)&data->saddr;
- socklen_t saddr_n = sizeof(data->saddr);
- k = recvfrom(data->fd, buf, n, data->flags, saddr, &saddr_n);
- return k;
-}
-
-/** Print to the underlying socket.
- *
- * @param s socket stream
- * @param msg format to use
- * @param args arguments
- * @return result of the print
- */
-static int socket_print(IOStream *s, const char *msg, va_list args){
- SocketData *data = socket_data(s);
- int n;
- n = vsnprintf(data->buf, data->buf_n - 1, msg, args);
- if(0 < n && n < data->buf_n){
- socket_write(s, data->buf, n);
- }
- return n;
-}
-
-/** Read a character from the underlying socket
- *
- * @param s socket stream
- * @return character read, IOSTREAM_EOF on end of socket (or error)
- */
-static int socket_getc(IOStream *s){
- char b;
- int n, c;
- n = socket_read(s, &b, 1);
- c = (n <= 0 ? IOSTREAM_EOF : b);
- return c;
-}
-
-/** Flush the socket (no-op).
- *
- * @param s socket stream
- * @return 0 on success, error code otherwise
- */
-static int socket_flush(IOStream *s){
- return 0;
-}
-
-/** Check if a socket stream has an error (no-op).
- *
- * @param s socket stream
- * @return 1 if has an error, 0 otherwise
- */
-static int socket_error(IOStream *s){
- // Read SOL_SOCKET/SO_ERROR ?
- return 0;
-}
-
-/** Close a socket stream.
- *
- * @param s socket stream to close
- * @return result of the close
- */
-static int socket_close(IOStream *s){
- SocketData *data = socket_data(s);
- return close(data->fd);
-}
-
-/** Free a socket stream.
- *
- * @param s socket stream
- */
-static void socket_free(IOStream *s){
- SocketData *data = socket_data(s);
- deallocate(data);
-}
-
-/** Create an IOStream for a socket.
- *
- * @param fd socket to wtap
- * @return new IOStream using fd for i/o
- */
-IOStream *socket_stream_new(int fd){
- int err = -ENOMEM;
- IOStream *io = NULL;
- SocketData *data = NULL;
-
- io = ALLOCATE(IOStream);
- if(!io) goto exit;
- io->methods = &socket_methods;
- data = ALLOCATE(SocketData);
- if(!data) goto exit;
- io->data = data;
- data->fd = fd;
- data->buf_n = sizeof(data->buf);
- err = 0;
- exit:
- if(err){
- if(io){
- if(data) deallocate(data);
- deallocate(io);
- io = NULL;
- }
- }
- return io;
-}
-
+++ /dev/null
-/* $Id: socket_stream.h,v 1.2 2004/03/04 17:38:13 mjw Exp $ */
-/*
- * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XEN_LIB_SOCKET_STREAM_H_
-#define _XEN_LIB_SOCKET_STREAM_H_
-
-#ifndef __KERNEL__
-#include "iostream.h"
-#include <stdio.h>
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-/** Data associated with a socket stream. */
-typedef struct SocketData {
- /** The socket file descriptor. */
- int fd;
- /** Source address from last read (recvfrom). */
- struct sockaddr_in saddr;
- /** Destination address for writes (sendto). */
- struct sockaddr_in daddr;
- /** Write flags (sendto). */
- int flags;
- /** Buffer size. */
- int buf_n;
- /** Buffer for formatted printing. */
- char buf[1024];
-} SocketData;
-
-extern IOStream *socket_stream_new(int fd);
-extern int socket_stream_data(IOStream *io, SocketData **data);
-extern int socket_stream_check(IOStream *io);
-extern int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr);
-extern int socket_stream_set_flags(IOStream *io, int flags);
-
-#endif
-#endif /* !_XEN_LIB_SOCKET_STREAM_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2001, 2002 Hewlett-Packard Company.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/** @file
- * IOStream subtype for input and output to strings.
- * Usable from user or kernel code (with __KERNEL__ defined).
- */
-
-#include "sys_string.h"
-#include "string_stream.h"
-#include "allocate.h"
-
-static int string_print(IOStream *io, const char *msg, va_list args);
-static int string_getc(IOStream *io);
-static int string_error(IOStream *io);
-static int string_close(IOStream *io);
-static void string_free(IOStream *io);
-
-/** Methods for a string stream. */
-static IOMethods string_methods = {
- //print: string_print,
- //getc: string_getc,
- error: string_error,
- close: string_close,
- free: string_free,
-};
-
-/** Get the string stream state.
- *
- * @param io string stream
- * @return state
- */
-static inline StringData *get_string_data(IOStream *io){
- return (StringData*)io->data;
-}
-
-/** Read a character from a string stream.
- *
- * @param io string stream
- * @return character read, IOSTREAM_EOF if no more input
- */
-static int string_getc(IOStream *io){
- StringData *data = get_string_data(io);
- int c = IOSTREAM_EOF;
- char *s = data->in;
-
- if(s && s < data->end){
- c = (unsigned)*s;
- data->in = s+1;
- }
- return c;
-}
-
-/** Print to a string stream.
- * Formats the data to an internal buffer and prints it.
- * The formatted data must fit into the internal buffer.
- *
- * @param io string stream
- * @param format print format
- * @param args print arguments
- * @return result of the print
- */
-static int string_print(IOStream *io, const char *msg, va_list args){
- StringData *data = get_string_data(io);
- int k = data->end - data->out;
- int n = vsnprintf(data->out, k, (char*)msg, args);
- if(n < 0 || n > k ){
- n = k;
- IOStream_close(io);
- } else {
- data->out += n;
- }
- return n;
-}
-
-/** Test if a string stream has an error.
- *
- * @param io string stream
- * @return 0 if ok, error code otherwise
- */
-static int string_error(IOStream *io){
- StringData *data = get_string_data(io);
- return data->out == NULL;
-}
-
-/** Close a string stream.
- *
- * @param io string stream
- * @return 0
- */
-static int string_close(IOStream *io){
- StringData *data = get_string_data(io);
- data->in = NULL;
- data->out = NULL;
- return 0;
-}
-
-/** Free a string stream.
- * The stream must have been allocated, not statically created.
- * The stream state is freed, but the underlying string is not.
- *
- * @param io string stream
- */
-static void string_free(IOStream *io){
- StringData *data = get_string_data(io);
- zero(data, sizeof(*data));
- deallocate(data);
-}
-
-/** Get the methods to use for a string stream.
- *
- * @return methods
- */
-IOMethods *string_stream_get_methods(void){
- return &string_methods;
-}
-
-/** Initialise a string stream, usually from static data.
- *
- * @param io address of IOStream to fill in
- * @param data address of StringData to fill in
- * @param s string to use
- * @param n length of the string
- */
-void string_stream_init(IOStream *io, StringData *data, char *s, int n){
- if(data && io){
- zero(data, sizeof(*data));
- data->string = (char*)s;
- data->in = data->string;
- data->out = data->string;
- data->size = n;
- data->end = data->string + n;
- zero(io, sizeof(*io));
- io->methods = &string_methods;
- io->data = data;
- }
-}
-
-/** Allocate and initialise a string stream.
- *
- * @param s string to use
- * @param n length of the string
- * @return new stream (free using IOStream_free)
- */
-IOStream *string_stream_new(char *s, int n){
- int ok = 0;
- StringData *data = ALLOCATE(StringData);
- IOStream *io = ALLOCATE(IOStream);
- if(data && io){
- ok = 1;
- string_stream_init(io, data, s, n);
- }
- if(!ok){
- deallocate(data);
- deallocate(io);
- io = NULL;
- }
- return io;
-}
+++ /dev/null
-/* $Id: string_stream.h,v 1.1 2003/08/22 14:25:48 mjw Exp $ */
-/*
- * Copyright (C) 2001, 2002 Hewlett-Packard Company.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _SP_STRING_STREAM_H_
-#define _SP_STRING_STREAM_H_
-
-#include "iostream.h"
-
-/** Internal state for a string stream.
- * Exposed here so that string streams can be statically created, using
- * string_stream_init().
- */
-typedef struct {
- /** The string used for input and ouput. */
- char *string;
- /** Output pointer. */
- char *out;
- /** Input pointer. */
- char *in;
- /** Length of string. */
- int size;
- /** End marker. */
- char *end;
-} StringData;
-
-extern IOMethods *string_stream_get_methods(void);
-extern IOStream *string_stream_new(char *s, int n);
-extern void string_stream_init(IOStream *stream, StringData *data, char *s, int n);
-
-#endif /* !_SP_STRING_STREAM_H_ */
+++ /dev/null
-/*
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library is
- * distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <stdarg.h>
-#include "sys_string.h"
-#include "lexis.h"
-#include "sys_net.h"
-#include "hash_table.h"
-#include "sxpr.h"
-
-#include <errno.h>
-#undef free
-
-/** @file
- * General representation of sxprs.
- * Includes print, equal, and free functions for the sxpr types.
- *
- * Zero memory containing an Sxpr will have the value ONONE - this is intentional.
- * When a function returning an sxpr cannot allocate memory we return ONOMEM.
- *
- */
-
-static int atom_print(IOStream *io, Sxpr obj, unsigned flags);
-static int atom_equal(Sxpr x, Sxpr y);
-static void atom_free(Sxpr obj);
-
-static int string_print(IOStream *io, Sxpr obj, unsigned flags);
-static int string_equal(Sxpr x, Sxpr y);
-static void string_free(Sxpr obj);
-
-static int cons_print(IOStream *io, Sxpr obj, unsigned flags);
-static int cons_equal(Sxpr x, Sxpr y);
-static void cons_free(Sxpr obj);
-
-static int null_print(IOStream *io, Sxpr obj, unsigned flags);
-static int none_print(IOStream *io, Sxpr obj, unsigned flags);
-static int int_print(IOStream *io, Sxpr obj, unsigned flags);
-static int bool_print(IOStream *io, Sxpr obj, unsigned flags);
-
-/** Type definitions. */
-static SxprType types[1024] = {
- [T_NONE] { type: T_NONE, name: "none", print: none_print },
- [T_NULL] { type: T_NULL, name: "null", print: null_print },
- [T_UINT] { type: T_UINT, name: "int", print: int_print, },
- [T_BOOL] { type: T_BOOL, name: "bool", print: bool_print, },
- [T_ATOM] { type: T_ATOM, name: "atom", print: atom_print,
- pointer: TRUE,
- free: atom_free,
- equal: atom_equal,
- },
- [T_STRING] { type: T_STRING, name: "string", print: string_print,
- pointer: TRUE,
- free: string_free,
- equal: string_equal,
- },
- [T_CONS] { type: T_CONS, name: "cons", print: cons_print,
- pointer: TRUE,
- free: cons_free,
- equal: cons_equal,
- },
-};
-
-/** Number of entries in the types array. */
-static int type_sup = sizeof(types)/sizeof(types[0]);
-
-/** Get the type definition for a given type code.
- *
- * @param ty type code
- * @return type definition or null
- */
-SxprType *get_sxpr_type(int ty){
- if(0 <= ty && ty < type_sup){
- return types+ty;
- }
- return NULL;
-}
-
-/** The default print function.
- *
- * @param io stream to print to
- * @param x sxpr to print
- * @param flags print flags
- * @return number of bytes written on success
- */
-int default_print(IOStream *io, Sxpr x, unsigned flags){
- return IOStream_print(io, "#<%u %lu>\n", get_type(x), get_ul(x));
-}
-
-/** The default equal function.
- * Uses eq().
- *
- * @param x sxpr to compare
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-int default_equal(Sxpr x, Sxpr y){
- return eq(x, y);
-}
-
-/** General sxpr print function.
- * Prints an sxpr on a stream using the print function for the sxpr type.
- * Printing is controlled by flags from the PrintFlags enum.
- * If PRINT_TYPE is in the flags the sxpr type is printed before the sxpr
- * (for debugging).
- *
- * @param io stream to print to
- * @param x sxpr to print
- * @param flags print flags
- * @return number of bytes written
- */
-int objprint(IOStream *io, Sxpr x, unsigned flags){
- SxprType *def = get_sxpr_type(get_type(x));
- ObjPrintFn *print_fn = (def && def->print ? def->print : default_print);
- int k = 0;
- if(!io) return k;
- if(flags & PRINT_TYPE){
- k += IOStream_print(io, "%s:", def->name);
- }
- k += print_fn(io, x, flags);
- return k;
-}
-
-/** General sxpr free function.
- * Frees an sxpr using the free function for its type.
- * Free functions must recursively free any subsxprs.
- * If no function is defined then the default is to
- * free sxprs whose type has pointer true.
- * Sxprs must not be used after freeing.
- *
- * @param x sxpr to free
- */
-void objfree(Sxpr x){
- SxprType *def = get_sxpr_type(get_type(x));
-
- if(def){
- if(def->free){
- def->free(x);
- } else if (def->pointer){
- hfree(x);
- }
- }
-}
-
-/** General sxpr equality function.
- * Compares x and y using the equal function for x.
- * Uses default_equal() if x has no equal function.
- *
- * @param x sxpr to compare
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-int objequal(Sxpr x, Sxpr y){
- SxprType *def = get_sxpr_type(get_type(x));
- ObjEqualFn *equal_fn = (def && def->equal ? def->equal : default_equal);
- return equal_fn(x, y);
-}
-
-/** Search for a key in an alist.
- * An alist is a list of conses, where the cars
- * of the conses are the keys. Compares keys using equality.
- *
- * @param k key
- * @param l alist to search
- * @return first element of l with car k, or ONULL
- */
-Sxpr assoc(Sxpr k, Sxpr l){
- for( ; CONSP(l) ; l = CDR(l)){
- Sxpr x = CAR(l);
- if(CONSP(x) && objequal(k, CAR(x))){
- return x;
- }
- }
- return ONULL;
-}
-
-/** Search for a key in an alist.
- * An alist is a list of conses, where the cars
- * of the conses are the keys. Compares keys using eq.
- *
- * @param k key
- * @param l alist to search
- * @return first element of l with car k, or ONULL
- */
-Sxpr assocq(Sxpr k, Sxpr l){
- for( ; CONSP(l); l = CDR(l)){
- Sxpr x = CAR(l);
- if(CONSP(x) && eq(k, CAR(x))){
- return x;
- }
- }
- return ONULL;
-}
-
-/** Add a new key and value to an alist.
- *
- * @param k key
- * @param l value
- * @param l alist
- * @return l with the new cell added to the front
- */
-Sxpr acons(Sxpr k, Sxpr v, Sxpr l){
- Sxpr x, y;
- x = cons_new(k, v);
- if(NOMEMP(x)) return x;
- y = cons_new(x, l);
- if(NOMEMP(y)) cons_free_cells(x);
- return y;
-}
-
-/** Test if a list contains an element.
- * Uses sxpr equality.
- *
- * @param l list
- * @param x element to look for
- * @return a tail of l with x as car, or ONULL
- */
-Sxpr cons_member(Sxpr l, Sxpr x){
- for( ; CONSP(l) && !eq(x, CAR(l)); l = CDR(l)){}
- return l;
-}
-
-/** Test if a list contains an element satisfying a test.
- * The test function is called with v and an element of the list.
- *
- * @param l list
- * @param test_fn test function to use
- * @param v value for first argument to the test
- * @return a tail of l with car satisfying the test, or 0
- */
-Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
- for( ; CONSP(l) && !test_fn(v, CAR(l)); l = CDR(l)){ }
- return l;
-}
-
-/** Test if the elements of list 't' are a subset of the elements
- * of list 's'. Element order is not significant.
- *
- * @param s element list to check subset of
- * @param t element list to check if is a subset
- * @return 1 if is a subset, 0 otherwise
- */
-int cons_subset(Sxpr s, Sxpr t){
- for( ; CONSP(t); t = CDR(t)){
- if(!CONSP(cons_member(s, CAR(t)))){
- return 0;
- }
- }
- return 1;
-}
-
-/** Test if two lists have equal sets of elements.
- * Element order is not significant.
- *
- * @param s list to check
- * @param t list to check
- * @return 1 if equal, 0 otherwise
- */
-int cons_set_equal(Sxpr s, Sxpr t){
- return cons_subset(s, t) && cons_subset(t, s);
-}
-
-#ifdef USE_GC
-/*============================================================================*/
-/* The functions inside this ifdef are only safe if GC is used.
- * Otherwise they may leak memory.
- */
-
-/** Remove an element from a list (GC only).
- * Uses sxpr equality and removes all instances, even
- * if there are more than one.
- *
- * @param l list to remove elements from
- * @param x element to remove
- * @return modified input list
- */
-Sxpr cons_remove(Sxpr l, Sxpr x){
- return cons_remove_if(l, eq, x);
-}
-
-/** Remove elements satisfying a test (GC only).
- * The test function is called with v and an element of the set.
- *
- * @param l list to remove elements from
- * @param test_fn function to use to decide if an element should be removed
- * @return modified input list
- */
-Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
- Sxpr prev = ONULL, elt, next;
-
- for(elt = l; CONSP(elt); elt = next){
- next = CDR(elt);
- if(test_fn(v, CAR(elt))){
- if(NULLP(prev)){
- l = next;
- } else {
- CDR(prev) = next;
- }
- }
- }
- return l;
-}
-
-/** Set the value for a key in an alist (GC only).
- * If the key is present, changes the value, otherwise
- * adds a new cell.
- *
- * @param k key
- * @param v value
- * @param l alist
- * @return modified or extended list
- */
-Sxpr setf(Sxpr k, Sxpr v, Sxpr l){
- Sxpr e = assoc(k, l);
- if(NULLP(e)){
- l = acons(k, v, l);
- } else {
- CAR(CDR(e)) = v;
- }
- return l;
-}
-/*============================================================================*/
-#endif /* USE_GC */
-
-/** Create a new atom with the given name.
- *
- * @param name the name
- * @return new atom
- */
-Sxpr atom_new(char *name){
- Sxpr n, obj = ONOMEM;
-
- n = string_new(name);
- if(NOMEMP(n)) goto exit;
- obj = HALLOC(ObjAtom, T_ATOM);
- if(NOMEMP(obj)) goto exit;
- OBJ_ATOM(obj)->name = n;
- exit:
- return obj;
-}
-
-/** Free an atom.
- *
- * @param obj to free
- */
-void atom_free(Sxpr obj){
- // Interned atoms are shared, so do not free.
- if(OBJ_ATOM(obj)->interned) return;
- objfree(OBJ_ATOM(obj)->name);
- hfree(obj);
-}
-
-/** Print an atom. Prints the atom name.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes printed
- */
-int atom_print(IOStream *io, Sxpr obj, unsigned flags){
- //return string_print(io, OBJ_ATOM(obj)->name, (flags | PRINT_RAW));
- return string_print(io, OBJ_ATOM(obj)->name, flags);
-}
-
-/** Atom equality.
- *
- * @param x to compare
- * @param y to compare
- * @return 1 if equal, 0 otherwise
- */
-int atom_equal(Sxpr x, Sxpr y){
- int ok;
- ok = eq(x, y);
- if(ok) goto exit;
- ok = ATOMP(y) && string_equal(OBJ_ATOM(x)->name, OBJ_ATOM(y)->name);
- if(ok) goto exit;
- ok = STRINGP(y) && string_equal(OBJ_ATOM(x)->name, y);
- exit:
- return ok;
-}
-
-/** Get the name of an atom.
- *
- * @param obj atom
- * @return name
- */
-char * atom_name(Sxpr obj){
- return string_string(OBJ_ATOM(obj)->name);
-}
-
-/** Get the C string from a string sxpr.
- *
- * @param obj string sxpr
- * @return string
- */
-char * string_string(Sxpr obj){
- return OBJ_STRING(obj);
-}
-
-/** Get the length of a string.
- *
- * @param obj string
- * @return length
- */
-int string_length(Sxpr obj){
- return strlen(OBJ_STRING(obj));
-}
-
-/** Create a new string. The input string is copied,
- * and must be null-terminated.
- *
- * @param s characters to put in the string
- * @return new sxpr
- */
-Sxpr string_new(char *s){
- int n = (s ? strlen(s) : 0);
- Sxpr obj;
- obj = halloc(n+1, T_STRING);
- if(!NOMEMP(obj)){
- char *str = OBJ_STRING(obj);
- strncpy(str, s, n);
- str[n] = '\0';
- }
- return obj;
-}
-
-/** Free a string.
- *
- * @param obj to free
- */
-void string_free(Sxpr obj){
- hfree(obj);
-}
-
-/** Determine if a string needs escapes when printed
- * using the given flags.
- *
- * @param str string to check
- * @param flags print flags
- * @return 1 if needs escapes, 0 otherwise
- */
-int needs_escapes(char *str, unsigned flags){
- char *c;
- int val = 0;
-
- if(str){
- for(c=str; *c; c++){
- if(in_alpha_class(*c)) continue;
- if(in_decimal_digit_class(*c)) continue;
- if(in_class(*c, "/._+:@~-")) continue;
- val = 1;
- break;
- }
- }
- //printf("\n> val=%d str=|%s|\n", val, str);
- return val;
-}
-
-/** Print a string to a stream, with escapes if necessary.
- *
- * @param io stream to print to
- * @param str string
- * @param flags print flags
- * @return number of bytes written
- */
-int _string_print(IOStream *io, char *str, unsigned flags){
- int k = 0;
- if((flags & PRINT_RAW) || !needs_escapes(str, flags)){
- k += IOStream_print(io, str);
- } else {
- k += IOStream_print(io, "\"");
- if(str){
- char *s;
- for(s = str; *s; s++){
- if(*s < ' ' || *s >= 127 ){
- switch(*s){
- case '\a': k += IOStream_print(io, "\\a"); break;
- case '\b': k += IOStream_print(io, "\\b"); break;
- case '\f': k += IOStream_print(io, "\\f"); break;
- case '\n': k += IOStream_print(io, "\\n"); break;
- case '\r': k += IOStream_print(io, "\\r"); break;
- case '\t': k += IOStream_print(io, "\\t"); break;
- case '\v': k += IOStream_print(io, "\\v"); break;
- default:
- // Octal escape;
- k += IOStream_print(io, "\\%o", *s);
- break;
- }
- } else if(*s == c_double_quote ||
- *s == c_single_quote ||
- *s == c_escape){
- k += IOStream_print(io, "\\%c", *s);
- } else {
- k+= IOStream_print(io, "%c", *s);
- }
- }
- }
- k += IOStream_print(io, "\"");
- }
- return k;
-}
-
-/** Print a string to a stream, with escapes if necessary.
- *
- * @param io stream to print to
- * @param obj string
- * @param flags print flags
- * @return number of bytes written
- */
-int string_print(IOStream *io, Sxpr obj, unsigned flags){
- return _string_print(io, OBJ_STRING(obj), flags);
-}
-
-/** Compare an sxpr with a string for equality.
- *
- * @param x string to compare with
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-int string_equal(Sxpr x, Sxpr y){
- int ok = 0;
- ok = eq(x,y);
- if(ok) goto exit;
- ok = has_type(y, T_STRING) && !strcmp(OBJ_STRING(x), OBJ_STRING(y));
- if(ok) goto exit;
- ok = has_type(y, T_ATOM) && !strcmp(OBJ_STRING(x), atom_name(y));
- exit:
- return ok;
-}
-
-/** Create a new cons cell.
- * The cell is ONOMEM if either argument is.
- *
- * @param car sxpr for the car
- * @param cdr sxpr for the cdr
- * @return new cons
- */
-Sxpr cons_new(Sxpr car, Sxpr cdr){
- Sxpr obj;
- if(NOMEMP(car) || NOMEMP(cdr)){
- obj = ONOMEM;
- } else {
- obj = HALLOC(ObjCons, T_CONS);
- if(!NOMEMP(obj)){
- ObjCons *z = OBJ_CONS(obj);
- z->car = car;
- z->cdr = cdr;
- }
- }
- return obj;
-}
-
-/** Push a new element onto a list.
- *
- * @param list list to add to
- * @param elt element to add
- * @return 0 if successful, error code otherwise
- */
-int cons_push(Sxpr *list, Sxpr elt){
- Sxpr l;
- l = cons_new(elt, *list);
- if(NOMEMP(l)) return -ENOMEM;
- *list = l;
- return 0;
-}
-
-/** Free a cons. Recursively frees the car and cdr.
- *
- * @param obj to free
- */
-void cons_free(Sxpr obj){
- Sxpr next;
- for(; CONSP(obj); obj = next){
- next = CDR(obj);
- objfree(CAR(obj));
- hfree(obj);
- }
- if(!NULLP(obj)){
- objfree(obj);
- }
-}
-
-/** Free a cons and its cdr cells, but not the car sxprs.
- * Does nothing if called on something that is not a cons.
- *
- * @param obj to free
- */
-void cons_free_cells(Sxpr obj){
- Sxpr next;
- for(; CONSP(obj); obj = next){
- next = CDR(obj);
- hfree(obj);
- }
-}
-
-/** Print a cons.
- * Prints the cons in list format if the cdrs are conses.
- * uses pair (dot) format if the last cdr is not a cons (or null).
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-int cons_print(IOStream *io, Sxpr obj, unsigned flags){
- int first = 1;
- int k = 0;
- k += IOStream_print(io, "(");
- for( ; CONSP(obj) ; obj = CDR(obj)){
- if(first){
- first = 0;
- } else {
- k += IOStream_print(io, " ");
- }
- k += objprint(io, CAR(obj), flags);
- }
- if(!NULLP(obj)){
- k += IOStream_print(io, " . ");
- k += objprint(io, obj, flags);
- }
- k += IOStream_print(io, ")");
- return (IOStream_error(io) ? -1 : k);
-}
-
-/** Compare a cons with another sxpr for equality.
- * If y is a cons, compares the cars and cdrs recursively.
- *
- * @param x cons to compare
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-int cons_equal(Sxpr x, Sxpr y){
- return CONSP(y) &&
- objequal(CAR(x), CAR(y)) &&
- objequal(CDR(x), CDR(y));
-}
-
-/** Return the length of a cons list.
- *
- * @param obj list
- * @return length
- */
-int cons_length(Sxpr obj){
- int count = 0;
- for( ; CONSP(obj); obj = CDR(obj)){
- count++;
- }
- return count;
-}
-
-/** Destructively reverse a cons list in-place.
- * If the argument is not a cons it is returned unchanged.
- *
- * @param l to reverse
- * @return reversed list
- */
-Sxpr nrev(Sxpr l){
- if(CONSP(l)){
- // Iterate down the cells in the list making the cdr of
- // each cell point to the previous cell. The last cell
- // is the head of the reversed list.
- Sxpr prev = ONULL;
- Sxpr cell = l;
- Sxpr next;
-
- while(1){
- next = CDR(cell);
- CDR(cell) = prev;
- if(!CONSP(next)) break;
- prev = cell;
- cell = next;
- }
- l = cell;
- }
- return l;
-}
-
-/** Print the null sxpr.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-static int null_print(IOStream *io, Sxpr obj, unsigned flags){
- return IOStream_print(io, "()");
-}
-
-/** Print the `unspecified' sxpr none.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-static int none_print(IOStream *io, Sxpr obj, unsigned flags){
- return IOStream_print(io, "<none>");
-}
-
-/** Print an integer.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-static int int_print(IOStream *io, Sxpr obj, unsigned flags){
- return IOStream_print(io, "%d", OBJ_INT(obj));
-}
-
-/** Print a boolean.
- *
- * @param io stream to print to
- * @param obj to print
- * @param flags print flags
- * @return number of bytes written
- */
-static int bool_print(IOStream *io, Sxpr obj, unsigned flags){
- return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false));
-}
-
-int sxprp(Sxpr obj, Sxpr name){
- return CONSP(obj) && objequal(CAR(obj), name);
-}
-
-/** Get the name of an element.
- *
- * @param obj element
- * @return name
- */
-Sxpr sxpr_name(Sxpr obj){
- Sxpr val = ONONE;
- if(CONSP(obj)){
- val = CAR(obj);
- } else if(STRINGP(obj) || ATOMP(obj)){
- val = obj;
- }
- return val;
-}
-
-int sxpr_is(Sxpr obj, char *s){
- if(ATOMP(obj)) return !strcmp(atom_name(obj), s);
- if(STRINGP(obj)) return !strcmp(string_string(obj), s);
- return 0;
-}
-
-int sxpr_elementp(Sxpr obj, Sxpr name){
- return CONSP(obj) && objequal(CAR(obj), name);
-}
-
-/** Get the attributes of an sxpr.
- *
- * @param obj sxpr
- * @return attributes
- */
-Sxpr sxpr_attributes(Sxpr obj){
- Sxpr val = ONULL;
- if(CONSP(obj)){
- obj = CDR(obj);
- if(CONSP(obj)){
- obj = CAR(obj);
- if(sxprp(obj, intern("@"))){
- val = CDR(obj);
- }
- }
- }
- return val;
-}
-
-Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def){
- Sxpr val = ONONE;
- val = assoc(sxpr_attributes(obj), key);
- if(CONSP(val) && CONSP(CDR(val))){
- val = CADR(def);
- } else {
- val = def;
- }
- return val;
-}
-
-/** Get the children of an sxpr.
- *
- * @param obj sxpr
- * @return children
- */
-Sxpr sxpr_children(Sxpr obj){
- Sxpr val = ONULL;
- if(CONSP(obj)){
- val = CDR(obj);
- if(CONSP(val) && sxprp(CAR(val), intern("@"))){
- val = CDR(val);
- }
- }
- return val;
-}
-
-Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def){
- Sxpr val = ONONE;
- Sxpr l;
- for(l = sxpr_children(obj); CONSP(l); l = CDR(l)){
- if(sxprp(CAR(l), name)){
- val = CAR(l);
- break;
- }
- }
- if(NONEP(val)) val = def;
- return val;
-}
-
-Sxpr sxpr_child0(Sxpr obj, Sxpr def){
- Sxpr val = ONONE;
- Sxpr l = sxpr_children(obj);
- if(CONSP(l)){
- val = CAR(l);
- } else {
- val = def;
- }
- return val;
-}
-
-Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def){
- Sxpr val = ONONE;
- val = sxpr_child(obj, name, ONONE);
- if(NONEP(val)){
- val = def;
- } else {
- val = sxpr_child0(val, def);
- }
- return val;
-}
-
-/** Table of interned symbols. Indexed by symbol name. */
-static HashTable *symbols = NULL;
-
-/** Hash function for entries in the symbol table.
- *
- * @param key to hash
- * @return hashcode
- */
-static Hashcode sym_hash_fn(void *key){
- return hash_string((char*)key);
-}
-
-/** Key equality function for the symbol table.
- *
- * @param x to compare
- * @param y to compare
- * @return 1 if equal, 0 otherwise
- */
-static int sym_equal_fn(void *x, void *y){
- return !strcmp((char*)x, (char*)y);
-}
-
-/** Entry free function for the symbol table.
- *
- * @param table the entry is in
- * @param entry being freed
- */
-static void sym_free_fn(HashTable *table, HTEntry *entry){
- if(entry){
- objfree(((ObjAtom*)entry->value)->name);
- HTEntry_free(entry);
- }
-}
-
-/** Initialize the symbol table.
- *
- * @return 0 on sucess, error code otherwise
- */
-static int init_symbols(void){
- symbols = HashTable_new(100);
- if(symbols){
- symbols->key_hash_fn = sym_hash_fn;
- symbols->key_equal_fn = sym_equal_fn;
- symbols->entry_free_fn = sym_free_fn;
- return 0;
- }
- return -1;
-}
-
-/** Cleanup the symbol table. Frees the table and all its symbols.
- */
-void cleanup_symbols(void){
- HashTable_free(symbols);
- symbols = NULL;
-}
-
-/** Get the interned symbol with the given name.
- * No new symbol is created.
- *
- * @return symbol or null
- */
-Sxpr get_symbol(char *sym){
- HTEntry *entry;
- if(!symbols){
- if(init_symbols()) return ONOMEM;
- return ONULL;
- }
- entry = HashTable_get_entry(symbols, sym);
- if(entry){
- return OBJP(T_ATOM, entry->value);
- } else {
- return ONULL;
- }
-}
-
-/** Get the interned symbol with the given name.
- * Creates a new symbol if necessary.
- *
- * @return symbol
- */
-Sxpr intern(char *sym){
- Sxpr symbol = get_symbol(sym);
- if(NULLP(symbol)){
- if(!symbols) return ONOMEM;
- symbol = atom_new(sym);
- if(!NOMEMP(symbol)){
- OBJ_ATOM(symbol)->interned = TRUE;
- HashTable_add(symbols, atom_name(symbol), get_ptr(symbol));
- }
- }
- return symbol;
-}
+++ /dev/null
-/*
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library is
- * distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _XEN_LIB_SXPR_H_
-#define _XEN_LIB_SXPR_H_
-
-#include <stdint.h>
-
-#include "hash_table.h"
-#include "iostream.h"
-#include "allocate.h"
-
-/** @file
- * Definitions for rules and sxprs.
- */
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-/** Sxpr type. */
-typedef int16_t TypeCode;
-
-/** A typed sxpr handle.*/
-typedef struct Sxpr {
- /** Sxpr type. */
- TypeCode type;
- union {
- /** Sxpr value. */
- unsigned long ul;
- /** Pointer. */
- void *ptr;
- } v;
-} Sxpr;
-
-/** Sxpr type to indicate out of memory. */
-#define T_NOMEM ((TypeCode)-1)
-/** The 'unspecified' sxpr. */
-#define T_NONE ((TypeCode)0)
-/** The empty list. */
-#define T_NULL ((TypeCode)1)
-/** Unsigned integer. */
-#define T_UINT ((TypeCode)2)
-/** A string. */
-#define T_STRING ((TypeCode)3)
-/** An atom. */
-#define T_ATOM ((TypeCode)4)
-/** A boolean. */
-#define T_BOOL ((TypeCode)5)
-
-/** A cons (pair or list). */
-#define T_CONS ((TypeCode)10)
-
-/** An error. */
-#define T_ERR ((TypeCode)40)
-
-/** An atom. */
-typedef struct ObjAtom {
- Sxpr name;
- Hashcode hashcode;
- int interned;
-} ObjAtom;
-
-/** A cons (pair). */
-typedef struct ObjCons {
- Sxpr car;
- Sxpr cdr;
-} ObjCons;
-
-/** A vector. */
-typedef struct ObjVector {
- int n;
- Sxpr data[0];
-} ObjVector;
-
-/** Flags for sxpr printing. */
-enum PrintFlags {
- PRINT_RAW = 0x001,
- PRINT_TYPE = 0x002,
- PRINT_PRETTY = 0x004,
- PRINT_NUM = 0x008,
-};
-
-/** An integer sxpr.
- *
- * @param ty type
- * @param val integer value
- */
-#define OBJI(ty, val) (Sxpr){ type: (ty), v: { ul: (val) }}
-
-/** A pointer sxpr.
- * If the pointer is non-null, returns an sxpr containing it.
- * If the pointer is null, returns ONOMEM.
- *
- * @param ty type
- * @param val pointer
- */
-#define OBJP(ty, val) ((val) ? (Sxpr){ type: (ty), v: { ptr: (val) }} : ONOMEM)
-
-/** Make an integer sxpr containing a pointer.
- *
- * @param val pointer
- */
-#define PTR(val) OBJP(T_UINT, (void*)(val))
-
-/** Make an integer sxpr.
- * @param x value
- */
-#define OINT(x) OBJI(T_UINT, x)
-
-/** Make an error sxpr.
- *
- * @param x value
- */
-#define OERR(x) OBJI(T_ERR, x)
-
-/** Out of memory constant. */
-#define ONOMEM OBJI(T_NOMEM, 0)
-
-/** The `unspecified' constant. */
-#define ONONE OBJI(T_NONE, 0)
-
-/** Empty list constant. */
-#define ONULL OBJI(T_NULL, 0)
-
-/** False constant. */
-#define OFALSE OBJI(T_BOOL, 0)
-
-/** True constant. */
-#define OTRUE OBJI(T_BOOL, 1)
-
-/* Recognizers for the various sxpr types. */
-#define ATOMP(obj) has_type(obj, T_ATOM)
-#define BOOLP(obj) has_type(obj, T_BOOL)
-#define CONSP(obj) has_type(obj, T_CONS)
-#define ERRP(obj) has_type(obj, T_ERR)
-#define INTP(obj) has_type(obj, T_UINT)
-#define NOMEMP(obj) has_type(obj, T_NOMEM)
-#define NONEP(obj) has_type(obj, T_NONE)
-#define NULLP(obj) has_type(obj, T_NULL)
-#define STRINGP(obj) has_type(obj, T_STRING)
-
-#define TRUEP(obj) get_ul(obj)
-
-/** Convert an sxpr to an unsigned integer. */
-#define OBJ_UINT(x) get_ul(x)
-/** Convert an sxpr to an integer. */
-#define OBJ_INT(x) (int)get_ul(x)
-
-/* Conversions of sxprs to their values.
- * No checking is done.
- */
-#define OBJ_STRING(x) ((char*)get_ptr(x))
-#define OBJ_CONS(x) ((ObjCons*)get_ptr(x))
-#define OBJ_ATOM(x) ((ObjAtom*)get_ptr(x))
-#define OBJ_SET(x) ((ObjSet*)get_ptr(x))
-#define CAR(x) (OBJ_CONS(x)->car)
-#define CDR(x) (OBJ_CONS(x)->cdr)
-
-#define CAAR(x) (CAR(CAR(x)))
-#define CADR(x) (CAR(CDR(x)))
-#define CDAR(x) (CDR(CAR(x)))
-#define CDDR(x) (CDR(CDR(x)))
-
-/** Get the integer value from an sxpr.
- *
- * @param obj sxpr
- * @return value
- */
-static inline unsigned long get_ul(Sxpr obj){
- return obj.v.ul;
-}
-
-/** Get the pointer value from an sxpr.
- *
- * @param obj sxpr
- * @return value
- */
-static inline void * get_ptr(Sxpr obj){
- return obj.v.ptr;
-}
-
-/** Create an sxpr containing a pointer.
- *
- * @param type typecode
- * @param val pointer
- * @return sxpr
- */
-static inline Sxpr obj_ptr(TypeCode type, void *val){
- return (Sxpr){ type: type, v: { ptr: val } };
-}
-
-/** Create an sxpr containing an integer.
- *
- * @param type typecode
- * @param val integer
- * @return sxpr
- */
-static inline Sxpr obj_ul(TypeCode type, unsigned long val){
- return (Sxpr){ type: type, v: { ul: val } };
-}
-
-/** Get the type of an sxpr.
- *
- * @param obj sxpr
- * @return type
- */
-static inline TypeCode get_type(Sxpr obj){
- return obj.type;
-}
-
-/** Check the type of an sxpr.
- *
- * @param obj sxpr
- * @param type to check
- * @return 1 if has the type, 0 otherwise
- */
-static inline int has_type(Sxpr obj, TypeCode type){
- return get_type(obj) == type;
-}
-
-/** Compare sxprs for literal equality of type and value.
- *
- * @param x sxpr to compare
- * @param y sxpr to compare
- * @return 1 if equal, 0 otherwise
- */
-static inline int eq(Sxpr x, Sxpr y){
- return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y)));
-}
-
-/** Checked version of CAR
- *
- * @param x sxpr
- * @return CAR if a cons, x otherwise
- */
-static inline Sxpr car(Sxpr x){
- return (CONSP(x) ? CAR(x) : x);
-}
-
-/** Checked version of CDR.
- *
- * @param x sxpr
- * @return CDR if a cons, null otherwise
- */
-static inline Sxpr cdr(Sxpr x){
- return (CONSP(x) ? CDR(x) : ONULL);
-}
-
-/** Allocate some memory and return an sxpr containing it.
- * Returns ONOMEM if allocation failed.
- *
- * @param n number of bytes to allocate
- * @param ty typecode
- * @return sxpr
- */
-static inline Sxpr halloc(size_t n, TypeCode ty){
- return OBJP(ty, allocate(n));
-}
-
-/** Allocate an sxpr containing a pointer to the given type.
- *
- * @param ty type (uses sizeof to determine how many bytes to allocate)
- * @param code typecode
- * @return sxpr, ONOMEM if allocation failed
- */
-#define HALLOC(ty, code) halloc(sizeof(ty), code)
-
-typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags);
-typedef int ObjEqualFn(Sxpr obj, Sxpr other);
-typedef void ObjFreeFn(Sxpr obj);
-
-/** An sxpr type definition. */
-typedef struct SxprType {
- TypeCode type;
- char *name;
- int pointer;
- ObjPrintFn *print;
- ObjEqualFn *equal;
- ObjFreeFn *free;
-} SxprType;
-
-
-extern SxprType *get_sxpr_type(int ty);
-
-/** Free the pointer in an sxpr.
- *
- * @param x sxpr containing a pointer
- */
-static inline void hfree(Sxpr x){
- deallocate(get_ptr(x));
-}
-
-extern int objprint(IOStream *io, Sxpr x, unsigned flags);
-extern int objequal(Sxpr x, Sxpr y);
-extern void objfree(Sxpr x);
-
-extern void cons_free_cells(Sxpr obj);
-extern Sxpr intern(char *s);
-
-extern Sxpr assoc(Sxpr k, Sxpr l);
-extern Sxpr assocq(Sxpr k, Sxpr l);
-extern Sxpr acons(Sxpr k, Sxpr v, Sxpr l);
-extern Sxpr nrev(Sxpr l);
-extern Sxpr cons_member(Sxpr l, Sxpr x);
-extern Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
-extern int cons_subset(Sxpr s, Sxpr t);
-extern int cons_set_equal(Sxpr s, Sxpr t);
-
-#ifdef USE_GC
-extern Sxpr cons_remove(Sxpr l, Sxpr x);
-extern Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
-#endif
-
-extern Sxpr atom_new(char *name);
-extern char * atom_name(Sxpr obj);
-
-extern Sxpr string_new(char *s);
-extern char * string_string(Sxpr obj);
-extern int string_length(Sxpr obj);
-
-extern Sxpr cons_new(Sxpr car, Sxpr cdr);
-extern int cons_push(Sxpr *list, Sxpr elt);
-extern int cons_length(Sxpr obj);
-
-Sxpr sxpr_name(Sxpr obj);
-int sxpr_is(Sxpr obj, char *s);
-int sxpr_elementp(Sxpr obj, Sxpr name);
-Sxpr sxpr_attributes(Sxpr obj);
-Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def);
-Sxpr sxpr_children(Sxpr obj);
-Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def);
-Sxpr sxpr_child0(Sxpr obj, Sxpr def);
-Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def);
-
-/** Create a new atom.
- *
- * @param s atom name
- * @return new atom
- */
-static inline Sxpr mkatom(char *s){
- return atom_new(s);
-}
-
-/** Create a new string sxpr.
- *
- * @param s string bytes (copied)
- * @return new string
- */
-static inline Sxpr mkstring(char *s){
- return string_new(s);
-}
-
-/** Create an integer sxpr.
- *
- * @param i value
- * @return sxpr
- */
-static inline Sxpr mkint(int i){
- return OBJI(T_UINT, i);
-}
-
-/** Create a boolean sxpr.
- *
- * @param b value
- * @return sxpr
- */
-static inline Sxpr mkbool(int b){
- return OBJI(T_BOOL, (b ? 1 : 0));
-}
-
-/* Constants used in parsing and printing. */
-#define k_list_open "("
-#define c_list_open '('
-#define k_list_close ")"
-#define c_list_close ')'
-#define k_true "true"
-#define k_false "false"
-
-#define c_var '$'
-#define c_escape '\\'
-#define c_single_quote '\''
-#define c_double_quote '"'
-#define c_string_open c_double_quote
-#define c_string_close c_double_quote
-#define c_data_open '['
-#define c_data_close ']'
-#define c_binary '*'
-#define c_eval '!'
-#define c_concat_open '{'
-#define c_concat_close '}'
-
-#endif /* ! _XEN_LIB_SXPR_H_ */
+++ /dev/null
-
-#ifdef __KERNEL__
-# include <linux/config.h>
-# include <linux/module.h>
-# include <linux/kernel.h>
-# include <linux/string.h>
-# include <linux/errno.h>
-#else
-# include <stdlib.h>
-# include <errno.h>
-#endif
-
-#include "iostream.h"
-#include "lexis.h"
-#include "sxpr_parser.h"
-#include "sys_string.h"
-
-/** @file
- * Sxpr parsing.
- *
- * So that the parser does not leak memory, all sxprs constructed by
- * the parser must be freed on error. On successful parse the sxpr
- * returned becomes the responsibility of the caller.
- *
- * @author Mike Wray <mike.wray@hpl.hp.com>
- */
-
-#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
-#define printf(fmt, args...) IOStream_print(iostdout, fmt, ##args)
-
-static void reset(Parser *z);
-static int inputchar(Parser *p, char c);
-static int savechar(Parser *p, char c);
-extern void parse_error(Parser *in);
-extern void parse_error_id(Parser *in, ParseErrorId id);
-
-static int begin_start(Parser *p, char c);
-static int state_start(Parser *p, char c);
-static int end_start(Parser *p);
-
-static int begin_comment(Parser *p, char c);
-static int state_comment(Parser *p, char c);
-static int end_comment(Parser *p);
-
-static int begin_string(Parser *p, char c);
-static int state_string(Parser *p, char c);
-static int end_string(Parser *p);
-static int state_escape(Parser *p, char c);
-static int state_octal(Parser *p, char c);
-static int state_hex(Parser *p, char c);
-
-static int begin_atom(Parser *p, char c);
-static int state_atom(Parser *p, char c);
-static int end_atom(Parser *p);
-
-static int state_list(Parser *p, char c);
-static int begin_list(Parser *p, char c);
-static int end_list(Parser *p);
-
-/** Print a parse error.
- *
- * @param in parser
- * @param msg format followed by printf arguments
- */
-void eprintf(Parser *in, char *msg, ...){
- va_list args;
- if(in->error_out){
- va_start(args, msg);
- IOStream_vprint(in->error_out, msg, args);
- va_end(args);
- }
-}
-
-/** Print a parse warning.
- *
- * @param in parser
- * @param msg format followed by printf arguments
- */
-void wprintf(Parser *in, char *msg, ...){
- va_list args;
- if(in->error_out){
- va_start(args, msg);
- IOStream_vprint(in->error_out, msg, args);
- va_end(args);
- }
-}
-
-/*============================================================================*/
-
-/** Record defining the message for a parse error. */
-typedef struct {
- ParseErrorId id;
- char *message;
-} ParseError;
-
-/** Format for printing parse error messages. */
-#define PARSE_ERR_FMT "parse error> line %3d, column %2d: %s"
-
-/** Message catalog for the parse error codes. */
-static ParseError catalog[] = {
- { PARSE_ERR_UNSPECIFIED, "unspecified error" },
- { PARSE_ERR_NOMEM, "out of memory" },
- { PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" },
- { PARSE_ERR_TOKEN_TOO_LONG, "token too long" },
- { PARSE_ERR_INVALID_SYNTAX, "syntax error" },
- { PARSE_ERR_INVALID_ESCAPE, "invalid escape" },
- { 0, NULL }
-};
-
-/** Number of entries in the message catalog. */
-const static int catalog_n = sizeof(catalog)/sizeof(ParseError);
-
-void ParserState_free(ParserState *z){
- if(!z) return;
- objfree(z->val);
- deallocate(z);
-}
-
-int ParserState_new(ParserStateFn *fn, ParserState *parent, ParserState **val){
- int err = 0;
- ParserState *z;
- z = ALLOCATE(ParserState);
- if(z){
- z->fn = fn;
- z->parent = parent;
- z->val = ONULL;
- } else {
- err = -ENOMEM;
- }
- if(!err) *val = z;
- return err;
-}
-
-/** Free a parser.
- * No-op if the parser is null.
- *
- * @param z parser
- */
-void Parser_free(Parser *z){
- if(!z) return;
- objfree(z->val);
- z->val = ONONE;
- deallocate(z);
-}
-
-/** Create a new parser. The error stream defaults to null.
- */
-Parser * Parser_new(void){
- Parser *z = ALLOCATE(Parser);
- int err = -ENOMEM;
-
- if(!z) goto exit;
- err = 0;
- reset(z);
- exit:
- if(err){
- Parser_free(z);
- z = NULL;
- }
- return z;
-}
-
-/** Get the next character.
- * Records the character read in the parser,
- * and sets the line and character counts.
- *
- * @param p parser
- * @return error flag: 0 on success, non-zero on error
- */
-static int inputchar(Parser *p, char c){
- int err = 0;
- if(c=='\n'){
- p->line_no++;
- p->char_no = 0;
- } else {
- p->char_no++;
- }
- return err;
-}
-
-static int savechar(Parser *p, char c){
- int err = 0;
- if(p->buf_i >= p->buf_n){
- err = -ENOMEM;
- goto exit;
- }
- p->buf[p->buf_i] = c;
- p->buf_i++;
- exit:
- return err;
-}
-
-int Parser_input_char(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- //skip;
- } else {
- inputchar(p, c);
- }
- if(!p->state){
- err = begin_start(p, c);
- if(err) goto exit;
- }
- err = p->state->fn(p, c);
- exit:
- return err;
-}
-
-int Parser_input_eof(Parser *p){
- int err = 0;
- p->eof = 1;
- err = Parser_input_char(p, IOSTREAM_EOF);
- return err;
-}
-
-int Parser_input(Parser *p, char *buf, int buf_n){
- int err = 0;
- int i = 0;
- if(buf_n <= 0){
- err = Parser_input_eof(p);
- goto exit;
- }
- for(i = 0; i<buf_n; i++){
- err = Parser_input_char(p, buf[i]);
- if(err) goto exit;
- }
- exit:
- err = (err < 0 ? err : buf_n);
- return err;
-}
-
-int Parser_push(Parser *p, ParserStateFn *fn){
- int err = 0;
- err = ParserState_new(fn, p->state, &p->state);
- return err;
-}
-
-int Parser_pop(Parser *p){
- int err = 0;
- ParserState *s = p->state;
- p->state = s->parent;
- ParserState_free(s);
- return err;
-}
-
-int Parser_return(Parser *p){
- int err = 0;
- Sxpr val = ONONE;
- if(!p->state){
- err = -EINVAL;
- goto exit;
- }
- val = p->state->val;
- p->state->val = ONONE;
- err = Parser_pop(p);
- if(err) goto exit;
- if(p->state){
- err = cons_push(&p->state->val, val);
- } else {
- val = nrev(val);
- p->val = val;
- }
- exit:
- if(err){
- objfree(val);
- }
- return err;
-}
-
-/** Determine if a character is a separator.
- *
- * @param p parser
- * @param c character to test
- * @return 1 if a separator, 0 otherwise
- */
-static int is_separator(Parser *p, char c){
- return in_sep_class(c);
-}
-
-/** Return the current token.
- * The return value points at the internal buffer, so
- * it must not be modified (or freed). Use copy_token() if you need a copy.
- *
- * @param p parser
- * @return token
- */
-char *peek_token(Parser *p){
- return p->buf;
-}
-
-/** Return a copy of the current token.
- * The returned value should be freed when finished with.
- *
- * @param p parser
- * @return copy of token
- */
-char *copy_token(Parser *p){
- return strdup(peek_token(p));
-}
-
-static int do_intern(Parser *p){
- int err = 0;
- Sxpr obj = intern(peek_token(p));
- if(NOMEMP(obj)){
- err = -ENOMEM;
- } else {
- p->state->val = obj;
- }
- return err;
-}
-
-static int do_string(Parser *p){
- int err = 0;
- Sxpr obj;
- obj = string_new(peek_token(p));
- if(NOMEMP(obj)){
- err = -ENOMEM;
- } else {
- p->state->val = obj;
- }
- return err;
-}
-
-void newtoken(Parser *p){
- memset(p->buf, 0, p->buf_n);
- p->buf_i = 0;
- p->tok_begin_line = p->line_no;
- p->tok_begin_char = p->char_no;
-}
-
-int get_escape(char c, char *d){
- int err = 0;
- switch(c){
- case 'a': *d = '\a'; break;
- case 'b': *d = '\b'; break;
- case 'f': *d = '\f'; break;
- case 'n': *d = '\n'; break;
- case 'r': *d = '\r'; break;
- case 't': *d = '\t'; break;
- case 'v': *d = '\v'; break;
- case c_escape: *d = c_escape; break;
- case c_single_quote: *d = c_single_quote; break;
- case c_double_quote: *d = c_double_quote; break;
- default:
- err = -EINVAL;
- }
- return err;
-}
-
-
-int begin_start(Parser *p, char c){
- return Parser_push(p, state_start);
-}
-
-int state_start(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- err = end_start(p);
- } else if(in_space_class(c)){
- //skip
- } else if(in_comment_class(c)){
- begin_comment(p, c);
- } else if(c == c_list_open){
- begin_list(p, c);
- } else if(c == c_list_close){
- parse_error(p);
- err = -EINVAL;
- } else if(in_string_quote_class(c)){
- begin_string(p, c);
- } else if(in_printable_class(c)){
- begin_atom(p, c);
- } else if(c == 0x04){
- //ctrl-D, EOT: end-of-text.
- Parser_input_eof(p);
- } else {
- parse_error(p);
- err = -EINVAL;
- }
- return err;
-}
-
-int end_start(Parser *p){
- int err = 0;
- err = Parser_return(p);
- return err;
-}
-
-int begin_comment(Parser *p, char c){
- int err = 0;
- err = Parser_push(p, state_comment);
- if(err) goto exit;
- err = inputchar(p, c);
- exit:
- return err;
-}
-
-int state_comment(Parser *p, char c){
- int err = 0;
- if(c == '\n' || at_eof(p)){
- err = end_comment(p);
- } else {
- err = inputchar(p, c);
- }
- return err;
-}
-
-int end_comment(Parser *p){
- return Parser_pop(p);
-}
-
-int begin_string(Parser *p, char c){
- int err = 0;
- err = Parser_push(p, state_string);
- if(err) goto exit;
- newtoken(p);
- p->state->delim = c;
- exit:
- return err;
-}
-
-int state_string(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- err = -EINVAL;
- } else if(c == p->state->delim){
- err = end_string(p);
- } else if(c == '\\'){
- err = Parser_push(p, state_escape);
- } else {
- err = savechar(p, c);
- }
- return err;
-}
-
-int end_string(Parser *p){
- int err = 0;
- err = do_string(p);
- if(err) goto exit;
- err = Parser_return(p);
- exit:
- return err;
-}
-
-int state_escape(Parser *p, char c){
- int err = 0;
- char d;
- if(at_eof(p)){
- parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- err = -EINVAL;
- goto exit;
- }
- if(get_escape(c, &d) == 0){
- err = savechar(p, d);
- if(err) goto exit;
- err = Parser_pop(p);
- } else if(c == 'x'){
- p->state->fn = state_hex;
- p->state->ival = 0;
- p->state->count = 0;
- } else {
- p->state->fn = state_octal;
- p->state->ival = 0;
- p->state->count = 0;
- err = Parser_input_char(p, c);
- }
- exit:
- return err;
-}
-
-int octaldone(Parser *p){
- int err = 0;
- char d = (char)(p->state->ival & 0xff);
- err = Parser_pop(p);
- if(err) goto exit;
- err = Parser_input_char(p, d);
- exit:
- return err;
-}
-
-int octaldigit(Parser *p, char c){
- int err = 0;
- p->state->ival *= 8;
- p->state->ival += c - '0';
- p->state->count++;
- if(err) goto exit;
- if(p->state->ival < 0 || p->state->ival > 0xff){
- parse_error(p);
- err = -EINVAL;
- goto exit;
- }
- if(p->state->count == 3){
- err = octaldone(p);
- }
- exit:
- return err;
-}
-
-int state_octal(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- err = -EINVAL;
- goto exit;
- } else if('0' <= c && c <= '7'){
- err = octaldigit(p, c);
- } else {
- err = octaldone(p);
- if(err) goto exit;
- Parser_input_char(p, c);
- }
- exit:
- return err;
-}
-
-int hexdone(Parser *p){
- int err = 0;
- char d = (char)(p->state->ival & 0xff);
- err = Parser_pop(p);
- if(err) goto exit;
- err = Parser_input_char(p, d);
- exit:
- return err;
-}
-
-int hexdigit(Parser *p, char c, char d){
- int err = 0;
- p->state->ival *= 16;
- p->state->ival += c - d;
- p->state->count++;
- if(err) goto exit;
- if(p->state->ival < 0 || p->state->ival > 0xff){
- parse_error(p);
- err = -EINVAL;
- goto exit;
- }
- if(p->state->count == 2){
- err = hexdone(p);
- }
- exit:
- return err;
-}
-
-int state_hex(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- err = -EINVAL;
- goto exit;
- } else if('0' <= c && c <= '9'){
- err = hexdigit(p, c, '0');
- } else if('A' <= c && c <= 'F'){
- err = hexdigit(p, c, 'A');
- } else if('a' <= c && c <= 'f'){
- err = hexdigit(p, c, 'a');
- } else if(p->state->count){
- err =hexdone(p);
- if(err) goto exit;
- Parser_input_char(p, c);
- }
- exit:
- return err;
-}
-
-int begin_atom(Parser *p, char c){
- int err = 0;
- err = Parser_push(p, state_atom);
- if(err) goto exit;
- newtoken(p);
- err = savechar(p, c);
- exit:
- return err;
-}
-
-int state_atom(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- err = end_atom(p);
- } else if(is_separator(p, c) ||
- in_space_class(c) ||
- in_comment_class(c)){
- err = end_atom(p);
- if(err) goto exit;
- err = Parser_input_char(p, c);
- } else {
- err = savechar(p, c);
- }
- exit:
- return err;
-}
-
-int end_atom(Parser *p){
- int err = 0;
- err = do_intern(p);
- if(err) goto exit;
- err = Parser_return(p);
- exit:
- return err;
-}
-
-int state_list(Parser *p, char c){
- int err = 0;
- if(at_eof(p)){
- parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
- err = -EINVAL;
- } else if(c == c_list_close){
- p->state->val = nrev(p->state->val);
- err = end_list(p);
- } else {
- err = state_start(p, c);
- }
- return err;
-
-}
-
-int begin_list(Parser *p, char c){
- return Parser_push(p, state_list);
-}
-
-int end_list(Parser *p){
- return Parser_return(p);
-}
-
-/** Reset the fields of a parser to initial values.
- *
- * @param z parser
- */
-static void reset(Parser *z){
- IOStream *error_out = z->error_out;
- int flags = z->flags;
- zero(z, sizeof(Parser));
- z->buf_n = sizeof(z->buf) - 1;
- z->buf_i = 0;
- z->line_no = 1;
- z->char_no = 0;
- z->error_out = error_out;
- z->flags = flags;
-}
-
-/** Set the parser error stream.
- * Parse errors are reported on the the error stream if it is non-null.
- *
- * @param z parser
- * @param error_out error stream
- */
-void set_error_stream(Parser *z, IOStream *error_out){
- if(z){
- z->error_out = error_out;
- }
-}
-
-/** Get the parser error message for an error code.
- *
- * @param id error code
- * @return error message (empty string if the code is unknown)
- */
-static char *get_message(ParseErrorId id){
- int i;
- for(i=0; i<catalog_n; i++){
- if(id == catalog[i].id){
- return catalog[i].message;
- }
- }
- return "";
-}
-
-/** Get the line number.
- *
- * @param in parser
- */
-int get_line(Parser *in){
- return in->line_no;
-}
-
-/** Get the column number.
- *
- * @param in parser
- */
-int get_column(Parser *in){
- return in->char_no;
-}
-
-/** Get the line number the current token started on.
- *
- * @param in parser
- */
-int get_tok_line(Parser *in){
- return in->tok_begin_line;
-}
-
-/** Get the column number the current token started on.
- *
- * @param in parser
- */
-int get_tok_column(Parser *in){
- return in->tok_begin_char;
-}
-
-/** Report a parse error.
- * Does nothing if the error stream is null or there is no error.
- *
- * @param in parser
- */
-static void report_error(Parser *in){
- if(in->error_out && in->err){
- char *msg = get_message(in->err);
- char *tok = peek_token(in);
- IOStream_print(in->error_out, PARSE_ERR_FMT,
- get_tok_line(in), get_tok_column(in), msg);
- if(tok && tok[0]){
- IOStream_print(in->error_out, " '%s'", tok);
- }
- IOStream_print(in->error_out, "\n");
- }
-}
-
-/** Get the error message for the current parse error code.
- * Does nothing if there is no error.
- *
- * @param in parser
- * @param buf where to place the message
- * @param n maximum number of characters to place in buf
- * @return current error code (zero for no error)
- */
-int parse_error_message(Parser *in, char *buf, int n){
- if(in->err){
- char *msg = get_message(in->err);
- snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in), get_tok_column(in), msg);
- }
- return in->err;
-}
-
-/** Flag an unspecified parse error. All subsequent reads will fail.
- *
- * @param in parser
- */
-void parse_error(Parser *in){
- parse_error_id(in, PARSE_ERR_INVALID_SYNTAX);
-}
-
-/** Flag a parse error. All subsequent reads will fail.
- * Does not change the parser error code if it is already set.
- *
- * @param in parser
- * @param id error code
- */
-void parse_error_id(Parser *in, ParseErrorId id){
- if(!in->err){
- in->err = id;
- report_error(in);
- }
-}
-
-/** Test if the parser's error flag is set.
- *
- * @param in parser
- * @return 1 if set, 0 otherwise
- */
-int has_error(Parser *in){
- return (in->err > 0);
-}
-
-/** Test if the parser is at end of input.
- *
- * @param in parser
- * @return 1 if at EOF, 0 otherwise
- */
-int at_eof(Parser *p){
- return p->eof;
-}
-
-#ifdef SXPR_PARSER_MAIN
-/* Stuff for standalone testing. */
-
-#include "file_stream.h"
-#include "string_stream.h"
-
-int stringof(Sxpr exp, char **s){
- int err = 0;
- if(ATOMP(exp)){
- *s = atom_name(exp);
- } else if(STRINGP(exp)){
- *s = string_string(exp);
- } else {
- err = -EINVAL;
- *s = NULL;
- }
- return err;
-}
-
-int child_string(Sxpr exp, Sxpr key, char **s){
- int err = 0;
- Sxpr val = sxpr_child_value(exp, key, ONONE);
- err = stringof(val, s);
- return err;
-}
-
-int intof(Sxpr exp, int *v){
- int err = 0;
- char *s;
- unsigned long l;
- if(INTP(exp)){
- *v = OBJ_INT(exp);
- } else {
- err = stringof(exp, &s);
- if(err) goto exit;
- err = convert_atoul(s, &l);
- *v = (int)l;
- }
- exit:
- return err;
-}
-
-int child_int(Sxpr exp, Sxpr key, int *v){
- int err = 0;
- Sxpr val = sxpr_child_value(exp, key, ONONE);
- err = intof(val, v);
- return err;
-}
-
-int eval_vnet(Sxpr exp){
- int err = 0;
- Sxpr oid = intern("id");
- int id;
- err = child_int(exp, oid, &id);
- if(err) goto exit;
- dprintf("> vnet id=%d\n", id);
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-int eval_connect(Sxpr exp){
- int err = 0;
- Sxpr ovif = intern("vif");
- Sxpr ovnet = intern("vnet");
- char *vif;
- int vnet;
-
- err = child_string(exp, ovif, &vif);
- if(err) goto exit;
- err = child_int(exp, ovnet, &vnet);
- if(err) goto exit;
- dprintf("> connect vif=%s vnet=%d\n", vif, vnet);
- exit:
- dprintf("< err=%d\n", err);
- return err;
-}
-
-int eval(Sxpr exp){
- int err = 0;
- Sxpr oconnect = intern("connect");
- Sxpr ovnet = intern("vnet");
-
- if(sxpr_elementp(exp, ovnet)){
- err = eval_vnet(exp);
- } else if(sxpr_elementp(exp, oconnect)){
- err = eval_connect(exp);
- } else {
- err = -EINVAL;
- }
- return err;
-}
-
-/** Main program for testing.
- * Parses input and prints it.
- *
- * @param argc number of arguments
- * @param argv arguments
- * @return error code
- */
-int main(int argc, char *argv[]){
- Parser *pin;
- int err = 0;
- char buf[1024];
- int k;
- Sxpr obj, l, x;
-
- pin = Parser_new();
- set_error_stream(pin, iostdout);
- dprintf("> parse...\n");
- while(1){
- k = fread(buf, 1, 1024, stdin);
- err = Parser_input(pin, buf, k);
- dprintf("> Parser_input=%d\n", err);
- if(k <= 0) break;
- }
- obj = pin->val;
- for(l = obj ; CONSP(l); l = CDR(l)){
- x = CAR(l);
- objprint(iostdout, x, 0); printf("\n");
- eval(x);
- }
- dprintf("> err=%d\n", err);
- return 0;
-}
-#endif
+++ /dev/null
-/*
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library is
- * distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XEN_LIB_SXPR_PARSER_H_
-#define _XEN_LIB_SXPR_PARSER_H_
-
-#include "sxpr.h"
-#include "iostream.h"
-
-/** @file
- * Sxpr parsing definitions.
- */
-
-/** Size of a parser input buffer.
- * Tokens read must fit into this size (including trailing null).
- */
-#define PARSER_BUF_SIZE 1024
-
-struct Parser;
-typedef int ParserStateFn(struct Parser *, char c);
-
-typedef struct ParserState {
- struct ParserState *parent;
- Sxpr val;
- int ival;
- int count;
- char delim;
- ParserStateFn *fn;
-} ParserState;
-
-/** Structure representing an input source for the parser.
- * Can read from any IOStream implementation.
- */
-typedef struct Parser {
- Sxpr val;
- /** Error reporting stream (null for no reports). */
- IOStream *error_out;
- int eof;
- /** Error flag. Non-zero if there has been a read error. */
- int err;
- /** Line number on input (from 1). */
- int line_no;
- /** Column number of input (reset on new line). */
- int char_no;
- /** Lookahead character. */
- char c;
- /** Buffer for reading tokens. */
- char buf[PARSER_BUF_SIZE];
- /** Size of token buffer. */
- int buf_n;
- int buf_i;
- /** Line the last token started on. */
- int tok_begin_line;
- /** Character number the last token started on. */
- int tok_begin_char;
- /** Parsing flags. */
- int flags;
- ParserState *state;
-} Parser;
-
-/** Parser error codes. */
-typedef enum {
- PARSE_ERR_NONE=0,
- PARSE_ERR_UNSPECIFIED,
- PARSE_ERR_NOMEM,
- PARSE_ERR_UNEXPECTED_EOF,
- PARSE_ERR_TOKEN_TOO_LONG,
- PARSE_ERR_INVALID_SYNTAX,
- PARSE_ERR_INVALID_ESCAPE,
-} ParseErrorId;
-
-
-/** Parser flags. */
-//enum {
-//};
-
-/** Raise some parser flags.
- *
- * @param in parser
- * @param flags flags mask
- */
-inline static void parser_flags_raise(Parser *in, int flags){
- in->flags |= flags;
-}
-
-/** Lower some parser flags.
- *
- * @param in parser
- * @param flags flags mask
- */
-inline static void parser_flags_lower(Parser *in, int flags){
- in->flags &= ~flags;
-}
-
-/** Clear all parser flags.
- *
- * @param in parser
- */
-inline static void parser_flags_clear(Parser *in){
- in->flags = 0;
-}
-
-extern void Parser_free(Parser *z);
-extern Parser * Parser_new(void);
-extern int Parser_input(Parser *p, char *buf, int buf_n);
-extern int Parser_input_eof(Parser *p);
-
-extern int parse_error_message(Parser *in, char *buf, int n);
-extern int has_error(Parser *in);
-extern int at_eof(Parser *in);
-
-#endif /* ! _XEN_LIB_SXPR_PARSER_H_ */
+++ /dev/null
-#ifndef _XENO_SYS_CTYPE_H_
-#define _XENO_SYS_CTYPE_H_
-/** @file
- ** Replacement for ctype include that can be used
- * from user or kernel code.
- */
-#ifdef __KERNEL__
-# include <linux/ctype.h>
-#else
-# include <ctype.h>
-#endif
-#endif /* ! _XENO_SYS_CTYPE_H_ */
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version. This library is
- * distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "sys_net.h"
-#include "sys_string.h"
-
-/** @file
- * All network data are kept in network order and only converted to
- * host order for display. Network data includes IP addresses, port numbers and
- * network masks.
- */
-
-/** Maximum value for a port. */
-#define PORT_MAX 0xffff
-
-/** Convert a number of bits to a network mask
- * for IP addresses. The number of bits must
- * be in the range 1-31.
- *
- * @param n number of bits to set in the mask
- * @return value with n high bits set (in network order)
- */
-unsigned long bits_to_mask(int n){
- unsigned long mask = (n ? (1 << 31) : 0);
- int i;
- for(i=1; i<n; i++){
- mask |= (mask >> 1);
- }
- return htonl(mask);
-}
-
-/** Convert a network mask to a number of bits.
- *
- * @param mask network mask in network order
- * @return number of bits in mask
- */
-int mask_to_bits(unsigned long mask){
- // Start with n set to the number of bits in the mask. Then reduce n by
- // the number of low zero bits in the mask.
- int n = 32;
- for(mask = ntohl(mask);
- (mask & 1)==0 && n>0;
- mask >>= 1){
- n--;
- }
- return n;
-}
-
-/** Get the index of the first occurrence of a character in a string.
- * Stops at end of string or after n characters.
- *
- * @param s input string
- * @param n maximum number of charactes to search
- * @param c character to look for
- * @return index of first occurrence, -1 if not found
- */
-inline static int indexof(const char *s, int n, char c){
- int i;
- for(i=0; i<n && *s; i++, s++){
- if(*s == c) return i;
- }
- return -1;
-}
-
-/** Convert an IPv4 address in dot notation into an unsigned long (in network order).
- *
- * @param s input string
- * @param address where to put the address
- * @return 0 on success, -1 on error
- */
-int get_inet_addr(const char *s, unsigned long *address){
- // Number of bits in a byte.
- const int BYTE_BITS = 8;
- // Number of bytes in a word.
- const int WORD_BYTES = 4;
- // Max value for a component of an address.
- const int ADDR_MAX = 255;
- // Separator for components of an address.
- const char dot = '.';
-
- int n;
- unsigned long addr = 0;
- unsigned long v;
- int i;
- int err = -1;
- // Bit shift for the current byte.
- int shift = BYTE_BITS * (WORD_BYTES - 1);
- char buf[64];
-
- n = strlen(s);
- if(n >= sizeof(buf)){
- goto exit;
- }
- for(i=0; i < WORD_BYTES; i++){
- int idx = indexof(s, n, dot);
- idx = (idx < 0 ? strlen(s) : idx);
- strncpy(buf, s, idx); buf[idx]='\0';
- if(convert_atoul(buf, &v)){
- goto exit;
- }
- if(v < 0 || v > ADDR_MAX){
- goto exit;
- }
- addr |= (v << shift);
- if(idx == n) break;
- shift -= BYTE_BITS;
- s += idx+1;
- }
- err = 0;
- exit:
- addr = htonl(addr);
- *address = (err ? 0 : addr);
- return err;
-}
-
-#ifdef __KERNEL__
-/** Convert an address in network order to IPv4 dot notation.
- * The return value is a static buffer which is overwritten on each call.
- *
- * @param inaddr address (in network order)
- * @return address in dot notation
- */
-char *inet_ntoa(struct in_addr inaddr){
- static char address[16] = {};
- uint32_t addr = ntohl(inaddr.s_addr);
- snprintf(address, sizeof(address), "%d.%d.%d.%d",
- (unsigned)((addr >> 24) & 0xff),
- (unsigned)((addr >> 16) & 0xff),
- (unsigned)((addr >> 8) & 0xff),
- (unsigned)((addr ) & 0xff));
- return address;
-}
-
-
-/** Convert a string in IPv4 dot notation to an int in network order.
- *
- * @param address address in dot notation
- * @param inp result of conversion (in network order)
- * @return 0 on success, error code on error
- */
-int inet_aton(const char *address, struct in_addr *inp){
- int err = 0;
- unsigned long addr;
-
- err = get_inet_addr(address, &addr);
- if(err) goto exit;
- inp->s_addr = addr;
- exit:
- return err;
-}
-#endif
-
-/** Convert a hostname or IPv4 address string to an address in network order.
- *
- * @param name input hostname or address string
- * @param address where to put the address
- * @return 1 if address found OK, 0 otherwise
- */
-int get_host_address(const char *name, unsigned long *address){
-#ifdef __KERNEL__
- return get_inet_addr(name, address) == 0;
-#else
- struct hostent *host = gethostbyname(name);
- if(!host){
- return 0;
- }
- *address = ((struct in_addr *)(host->h_addr))->s_addr;
- return 1;
-#endif
-}
-
-/** Convert a service name to a port (in network order).
- *
- * @param name service name
- * @param port where to put the port
- * @return 1 if service port found OK, 0 otherwise
- */
-int get_service_port(const char *name, unsigned long *port){
-#ifdef __KERNEL__
- return 0;
-#else
- struct servent *service;
- service = getservbyname(name, 0);
- if(!service){
- return 0;
- }
- *port = service->s_port;
- return 1;
-#endif
-}
-
-/** Convert a port number (in network order) to a service name.
- *
- * @param port the port number
- * @return service name if found OK, 0 otherwise
- */
-char *get_port_service(unsigned long port){
-#ifdef __KERNEL__
- return 0;
-#else
- struct servent *service = getservbyport(port, 0);
- return (service ? service->s_name : 0);
-#endif
-}
-
-/** Convert a decimal integer or service name to a port (in network order).
- *
- * @param s input to convert
- * @param port where to put the port
- * @return 1 if port found OK, 0 otherwise
- */
-int convert_service_to_port(const char *s, unsigned long *port){
- int ok = 0;
- unsigned long value;
- if(convert_atoul(s, &value)){
- ok = get_service_port(s, &value);
- } else {
- ok = (0 <= value) && (value <= PORT_MAX);
- value = htons((unsigned short)value);
- }
- *port = (ok ? value : 0);
- return ok;
-}
-
-#define MAC_ELEMENT_N 6 // Number of elements in a MAC address.
-#define MAC_DIGIT_N 2 // Number of digits in an element in a MAC address.
-#define MAC_LENGTH 17 //((MAC_ELEMENT_N * MAC_DIGIT_N) + MAC_ELEMENT_N - 1)
-
-/** Convert a mac address from a string of the form
- * XX:XX:XX:XX:XX:XX to numerical form (an array of 6 unsigned chars).
- * Each X denotes a hex digit: 0..9, a..f, A..F.
- * Also supports using '-' as the separator instead of ':'.
- *
- * @param mac_in string to convert
- * @param mac destination for the value
- * @return 0 on success, -1 on error
- */
-int mac_aton(const char *mac_in, unsigned char *mac){
- int err = 0;
- int i, j;
- const char *p;
- char sep = 0;
- unsigned char d;
- if(!mac_in || strlen(mac_in) != MAC_LENGTH){
- err = -1;
- goto exit;
- }
- for(i = 0, p = mac_in; i < MAC_ELEMENT_N; i++){
- d = 0;
- if(i){
- if(!sep){
- if(*p == ':' || *p == '-') sep = *p;
- }
- if(sep && *p == sep){
- p++;
- } else {
- err = -1;
- goto exit;
- }
- }
- for(j = 0; j < MAC_DIGIT_N; j++, p++){
- if(j) d <<= 4;
- if(*p >= '0' && *p <= '9'){
- d += (*p - '0');
- } else if(*p >= 'A' && *p <= 'F'){
- d += (*p - 'A') + 10;
- } else if(*p >= 'a' && *p <= 'f'){
- d += (*p - 'a') + 10;
- } else {
- err = -1;
- goto exit;
- }
- }
- mac[i] = d;
- }
- exit:
- return err;
-}
-
-/** Convert a MAC address from numerical form to a string.
- *
- * @param mac address to convert
- * @return static string value
- */
-char *mac_ntoa(const unsigned char *mac){
- static char buf[MAC_LENGTH + 1];
- int buf_n = sizeof(buf);
-
- memset(buf, buf_n, 0);
- snprintf(buf, buf_n, "%02x:%02x:%02x:%02x:%02x:%02x",
- mac[0], mac[1], mac[2],
- mac[3], mac[4], mac[5]);
- buf[buf_n - 1] = '\0';
- return buf;
-}
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XEN_LIB_SYS_NET_H_
-#define _XEN_LIB_SYS_NET_H_
-/** @file
- *
- * Replacement for standard network includes.
- * Works in user or kernel code.
- */
-
-extern int get_inet_addr(const char *s, unsigned long *address);
-extern unsigned long bits_to_mask(int n);
-extern int mask_to_bits(unsigned long mask);
-extern int get_host_address(const char *name, unsigned long *address);
-extern int get_service_port(const char *name, unsigned long *port);
-extern char *get_port_service(unsigned long port);
-extern int convert_service_to_port(const char *s, unsigned long *port);
-
-#ifdef __KERNEL__
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <asm/byteorder.h>
-
-#ifndef htonl
-#define htonl(x) __constant_htonl(x)
-#endif
-
-#ifndef ntohl
-#define ntohl(x) __constant_ntohl(x)
-#endif
-
-#ifndef htons
-#define htons(x) __constant_htons(x)
-#endif
-
-#ifndef ntohs
-#define ntohs(x) __constant_ntohs(x)
-#endif
-
-#include <linux/in.h>
-extern char *inet_ntoa(struct in_addr inaddr);
-extern int inet_aton(const char *address, struct in_addr *inp);
-
-#else
-
-#include <limits.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-
-#endif
-
-extern char *mac_ntoa(const unsigned char *macaddr);
-extern int mac_aton(const char *addr, unsigned char *macaddr);
-
-#endif /* !_SP_SYS_NET_H_ */
-
-
-
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef __KERNEL__
-# include <linux/config.h>
-# include <linux/module.h>
-# include <linux/kernel.h>
-# include <linux/errno.h>
-#else
-# include <errno.h>
-#endif
-
-#include "allocate.h"
-#include "sys_string.h"
-
-/** Set the base to use for converting a string to a number. Base is
- * hex if starts with 0x, otherwise decimal.
- *
- * @param s input string
- * @param base where to put the base
- * @return rest of s to parse as a number
- */
-inline static const char * convert_set_base(const char *s, int *base){
- *base = 10;
- if(s){
- if(*s=='0'){
- s++;
- if(*s=='x' || *s=='X'){
- *base = 16;
- s++;
- }
- }
- }
- return s;
-}
-
-/** Get the numerical value of a digit in the given base.
- *
- * @param c digit character
- * @param base to use
- * @return numerical value of digit in range 0..base-1 or
- * -1 if not in range for the base
- */
-inline static int convert_get_digit(char c, int base){
- int d;
-
- if('0'<=c && c<='9'){
- d = c - '0';
- } else if('a'<=c && c<='f'){
- d = c - 'a' + 10;
- } else if('A'<=c && c<='F'){
- d = c - 'A' + 10;
- } else {
- d = -1;
- }
- return (d < base ? d : -1);
-}
-
-/** Convert a string to an unsigned long by parsing it as a number.
- * Will accept hex or decimal in usual C syntax.
- *
- * @param str input string
- * @param val where to put the result
- * @return 0 if converted OK, negative otherwise
- */
-int convert_atoul(const char *str, unsigned long *val){
- int err = 0;
- unsigned long v = 0;
- int base;
- const char *s = str;
-
- if(!s) {
- err = -EINVAL;
- goto exit;
- }
- s = convert_set_base(s, &base);
- for( ; !err && *s; s++){
- int digit = convert_get_digit(*s, base);
- if(digit<0){
- err = -EINVAL;
- goto exit;
- }
- v *= base;
- v += digit;
- }
- exit:
- *val = (err ? 0 : v);
- return err;
-}
-
-/** Combine a directory path with a relative path to produce
- * a new path.
- *
- * @param s directory path
- * @param t relative path
- * @return new combined path s/t
- */
-int path_concat(char *s, char *t, char **val){
- int err = 0;
- int sn, tn, vn;
- char *v;
- sn = strlen(s);
- if(sn > 0 && s[sn-1] == '/'){
- sn--;
- }
- tn = strlen(t);
- if(tn > 0 && t[0] == '/'){
- tn--;
- }
- vn = sn+tn+1;
- v = (char*)allocate(vn+1);
- if(!v){
- err = -ENOMEM;
- goto exit;
- }
- strncpy(v, s, sn);
- v[sn] = '/';
- strncpy(v+sn+1, t, tn);
- v[vn] = '\0';
- exit:
- *val = (err ? NULL : v);
- return err;
-}
+++ /dev/null
-/*
- * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _XEN_LIB_SYS_STRING_H_
-#define _XEN_LIB_SYS_STRING_H_
-/** @file
- * Replacement for standard string includes.
- * Works in user or kernel code.
- */
-/*============================================================================*/
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <stdarg.h>
-#include "allocate.h"
-
-#if 0
-static inline int tolower(int c){
- return (c>='A' && c<='Z' ? (c-'A')+'a' : c);
-}
-#endif
-
-static inline int isalpha(int c){
- return (c>='A' && c<='Z') || (c>='a' && c<='z');
-}
-
-static inline int isdigit(int c){
- return (c>='0' && c<='9');
-}
-
-#if 0
-static inline int strcasecmp(const char *s1, const char *s2){
- int c1, c2;
-
- do {
- c1 = tolower(*s1++);
- c2 = tolower(*s2++);
- } while (c1 && c1 == c2);
- return c1 - c2;
-}
-#endif
-
-static inline char * strdup(const char *s){
- int n = (s ? 1+strlen(s) : 0);
- char *copy = (n ? allocate(n) : NULL);
- if(copy){
- strcpy(copy, s);
- }
- return copy;
-}
-
-/*============================================================================*/
-#else
-#include <string.h>
-#include <stdio.h>
-
-#ifndef _GNU_SOURCE
-static inline size_t strnlen(const char *s, size_t n){
- int k = 0;
- if(s){
- for(k=0; *s && k<n; s++, k++){}
- }
- return k;
-}
-#endif
-
-#endif
-/*============================================================================*/
-
-extern int convert_atoul(const char *s, unsigned long *v);
-extern int path_concat(char *s, char *t, char **val);
-
-#endif /* !_XEN_LIB_SYS_STRING_H_ */
+++ /dev/null
-/* $Id: xdr.c,v 1.3 2003/09/29 13:40:00 mjw Exp $ */
-#include "xdr.h"
-#include <errno.h>
-/** @file
- * XDR packer/unpacker for elements.
- *
- * string -> [T_STRING] [len:u32] <len bytes>
- * atom -> [T_ATOM] [len:u32] <len bytes>
- * uint -> [T_UINT] [value]
- * cons -> [T_CONS] <car> <cdr>
- * null -> [T_NULL]
- * none -> [T_NONE]
- * bool -> [T_BOOL] { 0:u8 | 1:u8 }
- *
- * types packed as u16.
- *
- * So (a b c) -> [T_CONS] a [T_CONS] b [T_CONS] c [T_NULL]
- * () -> [T_NULL]
- */
-
-int pack_bool(IOStream *io, int x){
- int err=0;
- err = IOStream_print(io, "%c", 0xff & x);
- if(err > 0) err = 0;
- return err;
-}
-
-int unpack_bool(IOStream *io, int *x){
- int err = 0;
- int c;
- c = IOStream_getc(io);
- *x = (c < 0 ? 0 : c);
- err = IOStream_error(io);
- if(c < 0 && !err) err = -EIO;
- return err;
-}
-
-int pack_ushort(IOStream *io, unsigned short x){
- int err=0;
- err = IOStream_print(io, "%c%c",
- 0xff & (x >> 8),
- 0xff & (x ));
- if(err > 0) err = 0;
- return err;
-}
-
-int unpack_ushort(IOStream *io, unsigned short *x){
- int err = 0;
- int i, c = 0;
- *x = 0;
- for(i = 0; i< 2; i++){
- c = IOStream_getc(io);
- if(c < 0) break;
- *x <<= 8;
- *x |= (0xff & c);
- }
- err = IOStream_error(io);
- if(c < 0 && !err) err = -EIO;
- return err;
-}
-
-int pack_uint(IOStream *io, unsigned int x){
- int err=0;
- err = IOStream_print(io, "%c%c%c%c",
- 0xff & (x >> 24),
- 0xff & (x >> 16),
- 0xff & (x >> 8),
- 0xff & (x ));
- if(err > 0) err = 0;
- return err;
-}
-
-int unpack_uint(IOStream *io, unsigned int *x){
- int err = 0;
- int i, c = 0;
- *x = 0;
- for(i = 0; i< 4; i++){
- c = IOStream_getc(io);
- if(c < 0) break;
- *x <<= 8;
- *x |= (0xff & c);
- }
- err = IOStream_error(io);
- if(c < 0 && !err) err = -EIO;
- return err;
-}
-
-int pack_string(IOStream *io, Sxpr x){
- int err = 0;
- int n = string_length(x);
- char *s = string_string(x);
- int i;
- err = pack_uint(io, n);
- if(err) goto exit;
- for(i = 0; i < n; i++){
- err = IOStream_print(io, "%c", s[i]);
- if(err < 0) break;
- }
- if(err > 0) err = 0;
- exit:
- return err;
-}
-
-int unpack_string(IOStream *io, Sxpr *x){
- int err;
- unsigned int n;
- int i, c = 0;
- char *s;
- Sxpr val = ONONE;
-
- err = unpack_uint(io, &n);
- if(err) goto exit;
- val = halloc(n+1, T_STRING);
- if(NOMEMP(val)){
- err = -ENOMEM;
- goto exit;
- }
- s = string_string(val);
- for(i=0; i<n; i++){
- c = IOStream_getc(io);
- if(c < 0) break;
- s[i] = (char)c;
- }
- s[n] = '\0';
- exit:
- err = IOStream_error(io);
- if(c < 0 && !err) err = -EIO;
- if(err){
- objfree(val);
- val = ONONE;
- }
- *x = val;
- return err;
-}
-
-int pack_cons(IOStream *io, Sxpr x){
- int err = 0;
- err = pack_sxpr(io, CAR(x));
- if(err) goto exit;
- err = pack_sxpr(io, CDR(x));
- exit:
- return err;
-}
-
-int unpack_cons(IOStream *io, Sxpr *x){
- int err = 0;
- Sxpr u = ONONE, v = ONONE, val = ONONE;
- err = unpack_sxpr(io, &u);
- if(err) goto exit;
- err = unpack_sxpr(io, &v);
- if(err) goto exit;
- val = cons_new(u, v);
- if(NOMEMP(val)){
- err = -ENOMEM;
- }
- exit:
- if(err){
- objfree(u);
- objfree(v);
- val = ONONE;
- }
- *x = val;
- return err;
-}
-
-int pack_sxpr(IOStream *io, Sxpr x){
- int err = 0;
- unsigned short type = get_type(x);
- err = pack_ushort(io, type);
- if(err) goto exit;
- switch(type){
- case T_NULL:
- break;
- case T_NONE:
- break;
- break;
- case T_BOOL:
- err = pack_bool(io, get_ul(x));
- break;
- case T_CONS:
- err = pack_cons(io, x);
- break;
- case T_ATOM:
- err = pack_string(io, OBJ_ATOM(x)->name);
- break;
- case T_STRING:
- err = pack_string(io, x);
- break;
- case T_UINT:
- err = pack_uint(io, get_ul(x));
- break;
- default:
- err = -EINVAL;
- IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type);
- break;
- }
- exit:
- return err;
-}
-
-int unpack_sxpr(IOStream *io, Sxpr *x){
- int err = 0;
- unsigned short type;
- unsigned int u;
- Sxpr val = ONONE, y;
-
- err = unpack_ushort(io, &type);
- if(err) goto exit;
- switch(type){
- case T_NULL:
- val = ONULL;
- break;
- case T_NONE:
- val = ONONE;
- break;
- case T_CONS:
- err = unpack_cons(io, &val);
- break;
- case T_BOOL:
- err = unpack_bool(io, &u);
- if(err) goto exit;
- val = (u ? OTRUE : OFALSE);
- break;
- case T_ATOM:
- err = unpack_string(io, &y);
- if(err) goto exit;
- val = intern(string_string(y));
- objfree(y);
- break;
- case T_STRING:
- err = unpack_string(io, &val);
- break;
- case T_UINT:
- err = unpack_uint(io, &u);
- if(err) goto exit;
- val = OBJI(type, u);
- break;
- default:
- err = -EINVAL;
- IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type);
- break;
- }
- exit:
- *x = (err ? ONONE : val);
- return err;
-}
+++ /dev/null
-/* $Id: xdr.h,v 1.2 2003/09/29 13:40:00 mjw Exp $ */
-#ifndef _SP_XDR_H_
-#define _SP_XDR_H_
-#include "iostream.h"
-#include "sxpr.h"
-int pack_uint(IOStream *out, unsigned int x);
-int unpack_uint(IOStream *in, unsigned int *x);
-int pack_string(IOStream *out, Sxpr x);
-int unpack_string(IOStream *in, Sxpr *x);
-int pack_cons(IOStream *out, Sxpr x);
-int unpack_cons(IOStream *in, Sxpr *x);
-int pack_sxpr(IOStream *out, Sxpr x);
-int unpack_sxpr(IOStream *in, Sxpr *x);
-#endif /* _SP_XDR_H_ */
--- /dev/null
+
+MAJOR = 1.3
+MINOR = 0
+SONAME = libxc.so.$(MAJOR)
+
+CC = gcc
+
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Make.defs
+
+vpath %.h $(XEN_HYPERVISOR_IFS)
+INCLUDES += -I $(XEN_HYPERVISOR_IFS)
+
+vpath %h $(XEN_LINUX_INCLUDE)
+INCLUDES += -I $(XEN_LINUX_INCLUDE)
+
+vpath %.h $(XEN_XU)
+INCLUDES += -I $(XEN_XU)
+
+vpath %c $(XEN_LIBXUTIL)
+INCLUDES += -I $(XEN_LIBXUTIL)
+
+LIB_SRCS :=
+LIB_SRCS += allocate.c
+#LIB_SRCS += enum.c
+LIB_SRCS += file_stream.c
+LIB_SRCS += gzip_stream.c
+#LIB_SRCS += hash_table.c
+LIB_SRCS += iostream.c
+#LIB_SRCS += kernel_stream.c
+#LIB_SRCS += lexis.c
+#LIB_SRCS += lzi_stream.c
+#LIB_SRCS += lzo_stream.c
+#LIB_SRCS += marshal.c
+#LIB_SRCS += socket_stream.c
+#LIB_SRCS += string_stream.c
+#LIB_SRCS += sxpr.c
+#LIB_SRCS += sxpr_parser.c
+LIB_SRCS += sys_net.c
+LIB_SRCS += sys_string.c
+#LIB_SRCS += xdr.c
+
+SRCS :=
+SRCS += xc_atropos.c
+SRCS += xc_bvtsched.c
+SRCS += xc_domain.c
+SRCS += xc_evtchn.c
+SRCS += xc_io.c
+SRCS += xc_linux_build.c
+SRCS += xc_linux_restore.c
+SRCS += xc_linux_save.c
+SRCS += xc_misc.c
+SRCS += xc_netbsd_build.c
+SRCS += xc_physdev.c
+SRCS += xc_private.c
+SRCS += xc_rrobin.c
+
+#SRCS += $(LIB_SRCS)
+
+CFLAGS += -Wall
+CFLAGS += -Werror
+CFLAGS += -g
+CFLAGS += -O3
+CFLAGS += -fno-strict-aliasing
+CFLAGS += $(INCLUDES)
+# Get gcc to generate the dependencies for us.
+CFLAGS += -Wp,-MD,.$(@F).d
+DEPS = .*.d
+
+OBJS = $(patsubst %.c,%.o,$(SRCS))
+
+LIB = libxc.so libxc.so.$(MAJOR) libxc.so.$(MAJOR).$(MINOR)
+
+all: check-for-zlib $(LIB)
+
+check-for-zlib:
+ @if [ ! -e /usr/include/zlib.h ]; then \
+ echo "***********************************************************"; \
+ echo "ERROR: install zlib header files (http://www.gzip.org/zlib)"; \
+ echo "***********************************************************"; \
+ false; \
+ fi
+
+install: all
+ mkdir -p $(prefix)/usr/lib
+ mkdir -p $(prefix)/usr/include
+ install -m0755 $(LIB) $(prefix)/usr/lib
+ install -m0644 xc.h $(prefix)/usr/include
+
+clean:
+ $(RM) *.a *.so *.o *.rpm $(LIB)
+ $(RM) *~
+ $(RM) $(DEPS)
+
+rpm: all
+ rm -rf staging
+ mkdir staging
+ mkdir staging/i386
+ rpmbuild --define "staging$$PWD/staging" --define '_builddir.' \
+ --define "_rpmdir$$PWD/staging" -bb rpm.spec
+ mv staging/i386/*.rpm .
+ rm -rf staging
+
+libxc.so:
+ ln -sf libxc.so.$(MAJOR) $@
+libxc.so.$(MAJOR):
+ ln -sf libxc.so.$(MAJOR).$(MINOR) $@
+libxc.so.$(MAJOR).$(MINOR): $(OBJS)
+ $(CC) -Wl,-soname -Wl,$(SONAME) -shared -o $@ $^ ../libxutil/libxutil.a -lz
+
+%.o: %.c Makefile
+
+# $(CC) $(CFLAGS) -o $@ $<
+
+-include $(DEPS)
--- /dev/null
+Summary: Xen control interface library
+Name: xen-internal-library
+Version: 1.2
+Release: 1
+License: Xen
+Group: Xen
+BuildRoot: %{staging}
+%description
+Library to make it easier to access the Xen control interfaces.
+
+%pre
+%preun
+%install
+install -m 0755 -d $RPM_BUILD_ROOT/lib
+install -m 0755 libxc.a $RPM_BUILD_ROOT/lib/libxc.a
+install -m 0755 libxc.so $RPM_BUILD_ROOT/lib/libxc.so
+install -m 0755 -d $RPM_BUILD_ROOT/include
+install -m 0644 xc.h $RPM_BUILD_ROOT/include/xc.h
+%clean
+%post
+%postun
+%files
+%defattr(-,root,root)
+%dir /lib
+/lib/libxc.a
+/lib/libxc.so
+%dir /include
+/include/xc.h
--- /dev/null
+/******************************************************************************
+ * xc.h
+ *
+ * A library for low-level access to the Xen control interfaces.
+ *
+ * Copyright (c) 2003, K A Fraser.
+ */
+
+#ifndef __XC_H__
+#define __XC_H__
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+typedef unsigned long long u64;
+typedef signed char s8;
+typedef signed short s16;
+typedef signed long s32;
+typedef signed long long s64;
+
+/* Obtain or relinquish a handle on the 'xc' library. */
+int xc_interface_open(void);
+int xc_interface_close(int xc_handle);
+
+typedef struct {
+ u32 domid;
+ unsigned int cpu;
+ unsigned int dying:1, crashed:1, shutdown:1,
+ paused:1, blocked:1, running:1;
+ unsigned int shutdown_reason; /* only meaningful if shutdown==1 */
+ unsigned long nr_pages;
+ unsigned long shared_info_frame;
+ u64 cpu_time;
+#define XC_DOMINFO_MAXNAME 16
+ char name[XC_DOMINFO_MAXNAME];
+ unsigned long max_memkb;
+} xc_dominfo_t;
+
+typedef struct xc_shadow_control_stats_st
+{
+ unsigned long fault_count;
+ unsigned long dirty_count;
+ unsigned long dirty_net_count;
+ unsigned long dirty_block_count;
+} xc_shadow_control_stats_t;
+
+int xc_domain_create(int xc_handle,
+ unsigned int mem_kb,
+ const char *name,
+ int cpu,
+ u32 *pdomid);
+int xc_domain_pause(int xc_handle,
+ u32 domid);
+int xc_domain_unpause(int xc_handle,
+ u32 domid);
+int xc_domain_destroy(int xc_handle,
+ u32 domid);
+int xc_domain_pincpu(int xc_handle,
+ u32 domid,
+ int cpu);
+int xc_domain_getinfo(int xc_handle,
+ u32 first_domid,
+ unsigned int max_doms,
+ xc_dominfo_t *info);
+
+int xc_shadow_control(int xc_handle,
+ u32 domid,
+ unsigned int sop,
+ unsigned long *dirty_bitmap,
+ unsigned long pages,
+ xc_shadow_control_stats_t *stats);
+
+
+#define XCFLAGS_VERBOSE 1
+#define XCFLAGS_LIVE 2
+#define XCFLAGS_DEBUG 4
+
+struct XcIOContext;
+int xc_linux_save(int xc_handle, struct XcIOContext *ioctxt);
+int xc_linux_restore(int xc_handle, struct XcIOContext *ioctxt);
+
+int xc_linux_build(int xc_handle,
+ u32 domid,
+ const char *image_name,
+ const char *ramdisk_name,
+ const char *cmdline,
+ unsigned int control_evtchn,
+ unsigned long flags);
+
+int xc_netbsd_build(int xc_handle,
+ u32 domid,
+ const char *image_name,
+ const char *cmdline,
+ unsigned int control_evtchn);
+
+int xc_bvtsched_global_set(int xc_handle,
+ unsigned long ctx_allow);
+
+int xc_bvtsched_domain_set(int xc_handle,
+ u32 domid,
+ unsigned long mcuadv,
+ unsigned long warp,
+ unsigned long warpl,
+ unsigned long warpu);
+
+int xc_bvtsched_global_get(int xc_handle,
+ unsigned long *ctx_allow);
+
+int xc_bvtsched_domain_get(int xc_handle,
+ u32 domid,
+ unsigned long *mcuadv,
+ unsigned long *warp,
+ unsigned long *warpl,
+ unsigned long *warpu);
+
+int xc_atropos_domain_set(int xc_handle,
+ u32 domid,
+ u64 period, u64 slice, u64 latency,
+ int xtratime);
+
+int xc_atropos_domain_get(int xc_handle,
+ u32 domid,
+ u64* period, u64 *slice, u64 *latency,
+ int *xtratime);
+
+int xc_rrobin_global_set(int xc_handle, u64 slice);
+
+int xc_rrobin_global_get(int xc_handle, u64 *slice);
+
+#define DOMID_SELF (0x7FFFFFFEU)
+
+typedef struct {
+#define EVTCHNSTAT_closed 0 /* Chennel is not in use. */
+#define EVTCHNSTAT_unbound 1 /* Channel is not bound to a source. */
+#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */
+#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */
+#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */
+ int status;
+ union {
+ struct {
+ u32 dom;
+ int port;
+ } interdomain;
+ int pirq;
+ int virq;
+ } u;
+} xc_evtchn_status_t;
+
+int xc_evtchn_bind_interdomain(int xc_handle,
+ u32 dom1, /* may be DOMID_SELF */
+ u32 dom2, /* may be DOMID_SELF */
+ int *port1,
+ int *port2);
+int xc_evtchn_bind_virq(int xc_handle,
+ int virq,
+ int *port);
+int xc_evtchn_close(int xc_handle,
+ u32 dom, /* may be DOMID_SELF */
+ int port);
+int xc_evtchn_send(int xc_handle,
+ int local_port);
+int xc_evtchn_status(int xc_handle,
+ u32 dom, /* may be DOMID_SELF */
+ int port,
+ xc_evtchn_status_t *status);
+
+int xc_physdev_pci_access_modify(int xc_handle,
+ u32 domid,
+ int bus,
+ int dev,
+ int func,
+ int enable);
+
+int xc_readconsolering(int xc_handle,
+ char *str,
+ unsigned int max_chars,
+ int clear);
+
+typedef struct {
+ int ht_per_core;
+ int cores;
+ unsigned long total_pages;
+ unsigned long free_pages;
+ unsigned long cpu_khz;
+} xc_physinfo_t;
+
+int xc_physinfo(int xc_handle,
+ xc_physinfo_t *info);
+
+int xc_domain_setname(int xc_handle,
+ u32 domid,
+ char *name);
+
+int xc_domain_setinitialmem(int xc_handle,
+ u32 domid,
+ unsigned int initial_memkb);
+
+int xc_domain_setmaxmem(int xc_handle,
+ u32 domid,
+ unsigned int max_memkb);
+
+
+#endif /* __XC_H__ */
--- /dev/null
+/******************************************************************************
+ * xc_atropos.c
+ *
+ * API for manipulating parameters of the Atropos scheduler.
+ *
+ * by Mark Williamson, Copyright (c) 2004 Intel Research Cambridge.
+ */
+
+#include "xc_private.h"
+
+int xc_atropos_domain_set(int xc_handle,
+ u32 domid, u64 period, u64 slice, u64 latency,
+ int xtratime)
+{
+ dom0_op_t op;
+ struct atropos_adjdom *p = &op.u.adjustdom.u.atropos;
+
+ op.cmd = DOM0_ADJUSTDOM;
+ op.u.adjustdom.domain = (domid_t)domid;
+ op.u.adjustdom.sched_id = SCHED_ATROPOS;
+ op.u.adjustdom.direction = SCHED_INFO_PUT;
+
+ p->nat_period = period;
+ p->nat_slice = slice;
+ p->latency = latency;
+ p->xtratime = xtratime;
+
+ return do_dom0_op(xc_handle, &op);
+}
+
+int xc_atropos_domain_get(int xc_handle, u32 domid, u64 *period,
+ u64 *slice, u64 *latency, int *xtratime)
+{
+ dom0_op_t op;
+ int ret;
+ struct atropos_adjdom *p = &op.u.adjustdom.u.atropos;
+
+ op.cmd = DOM0_ADJUSTDOM;
+ op.u.adjustdom.domain = (domid_t)domid;
+ op.u.adjustdom.sched_id = SCHED_ATROPOS;
+ op.u.adjustdom.direction = SCHED_INFO_GET;
+
+ ret = do_dom0_op(xc_handle, &op);
+
+ *period = p->nat_period;
+ *slice = p->nat_slice;
+ *latency = p->latency;
+ *xtratime = p->xtratime;
+
+ return ret;
+}
--- /dev/null
+/******************************************************************************
+ * xc_bvtsched.c
+ *
+ * API for manipulating parameters of the Borrowed Virtual Time scheduler.
+ *
+ * Copyright (c) 2003, K A Fraser.
+ */
+
+#include "xc_private.h"
+
+int xc_bvtsched_global_set(int xc_handle,
+ unsigned long ctx_allow)
+{
+ dom0_op_t op;
+
+ op.cmd = DOM0_SCHEDCTL;
+ op.u.schedctl.sched_id = SCHED_BVT;
+ op.u.schedctl.direction = SCHED_INFO_PUT;
+ op.u.schedctl.u.bvt.ctx_allow = ctx_allow;
+
+ return do_dom0_op(xc_handle, &op);
+}
+
+int xc_bvtsched_global_get(int xc_handle,
+ unsigned long *ctx_allow)
+{
+ dom0_op_t op;
+ int ret;
+
+ op.cmd = DOM0_SCHEDCTL;
+ op.u.schedctl.sched_id = SCHED_BVT;
+ op.u.schedctl.direction = SCHED_INFO_GET;
+
+ ret = do_dom0_op(xc_handle, &op);
+
+ *ctx_allow = op.u.schedctl.u.bvt.ctx_allow;
+
+ return ret;
+}
+
+int xc_bvtsched_domain_set(int xc_handle,
+ u32 domid,
+ unsigned long mcuadv,
+ unsigned long warp,
+ unsigned long warpl,
+ unsigned long warpu)
+{
+ dom0_op_t op;
+ struct bvt_adjdom *bvtadj = &op.u.adjustdom.u.bvt;
+
+ op.cmd = DOM0_ADJUSTDOM;
+ op.u.adjustdom.domain = (domid_t)domid;
+ op.u.adjustdom.sched_id = SCHED_BVT;
+ op.u.adjustdom.direction = SCHED_INFO_PUT;
+
+ bvtadj->mcu_adv = mcuadv;
+ bvtadj->warp = warp;
+ bvtadj->warpl = warpl;
+ bvtadj->warpu = warpu;
+ return do_dom0_op(xc_handle, &op);
+}
+
+
+int xc_bvtsched_domain_get(int xc_handle,
+ u32 domid,
+ unsigned long *mcuadv,
+ unsigned long *warp,
+ unsigned long *warpl,
+ unsigned long *warpu)
+{
+
+ dom0_op_t op;
+ int ret;
+ struct bvt_adjdom *adjptr = &op.u.adjustdom.u.bvt;
+
+ op.cmd = DOM0_ADJUSTDOM;
+ op.u.adjustdom.domain = (domid_t)domid;
+ op.u.adjustdom.sched_id = SCHED_BVT;
+ op.u.adjustdom.direction = SCHED_INFO_GET;
+
+ ret = do_dom0_op(xc_handle, &op);
+
+ *mcuadv = adjptr->mcu_adv;
+ *warp = adjptr->warp;
+ *warpl = adjptr->warpl;
+ *warpu = adjptr->warpu;
+ return ret;
+}
--- /dev/null
+/******************************************************************************
+ * xc_domain.c
+ *
+ * API for manipulating and obtaining information on domains.
+ *
+ * Copyright (c) 2003, K A Fraser.
+ */
+
+#include "xc_private.h"
+
+int xc_domain_create(int xc_handle,
+ unsigned int mem_kb,
+ const char *name,
+ int cpu,
+ u32 *pdomid)
+{
+ int err;
+ dom0_op_t op;
+
+ op.cmd = DOM0_CREATEDOMAIN;
+ op.u.createdomain.memory_kb = mem_kb;
+ strncpy(op.u.createdomain.name, name, MAX_DOMAIN_NAME);
+ op.u.createdomain.name[MAX_DOMAIN_NAME-1] = '\0';
+ op.u.createdomain.cpu = cpu;
+
+ if ( (err = do_dom0_op(xc_handle, &op)) == 0 )
+ *pdomid = (u32)op.u.createdomain.domain;
+
+ return err;
+}
+
+
+int xc_domain_pause(int xc_handle,
+ u32 domid)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_PAUSEDOMAIN;
+ op.u.pausedomain.domain = (domid_t)domid;
+ return do_dom0_op(xc_handle, &op);
+}
+
+
+int xc_domain_unpause(int xc_handle,
+ u32 domid)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_UNPAUSEDOMAIN;
+ op.u.unpausedomain.domain = (domid_t)domid;
+ return do_dom0_op(xc_handle, &op);
+}
+
+
+int xc_domain_destroy(int xc_handle,
+ u32 domid)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_DESTROYDOMAIN;
+ op.u.destroydomain.domain = (domid_t)domid;
+ return do_dom0_op(xc_handle, &op);
+}
+
+int xc_domain_pincpu(int xc_handle,
+ u32 domid,
+ int cpu)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_PINCPUDOMAIN;
+ op.u.pincpudomain.domain = (domid_t)domid;
+ op.u.pincpudomain.cpu = cpu;
+ return do_dom0_op(xc_handle, &op);
+}
+
+
+int xc_domain_getinfo(int xc_handle,
+ u32 first_domid,
+ unsigned int max_doms,
+ xc_dominfo_t *info)
+{
+ unsigned int nr_doms;
+ u32 next_domid = first_domid;
+ dom0_op_t op;
+
+ for ( nr_doms = 0; nr_doms < max_doms; nr_doms++ )
+ {
+ op.cmd = DOM0_GETDOMAININFO;
+ op.u.getdomaininfo.domain = (domid_t)next_domid;
+ op.u.getdomaininfo.ctxt = NULL; /* no exec context info, thanks. */
+ if ( do_dom0_op(xc_handle, &op) < 0 )
+ break;
+ info->domid = (u32)op.u.getdomaininfo.domain;
+
+ info->cpu =
+ (op.u.getdomaininfo.flags>>DOMFLAGS_CPUSHIFT) & DOMFLAGS_CPUMASK;
+
+ info->dying = !!(op.u.getdomaininfo.flags & DOMFLAGS_DYING);
+ info->crashed = !!(op.u.getdomaininfo.flags & DOMFLAGS_CRASHED);
+ info->shutdown = !!(op.u.getdomaininfo.flags & DOMFLAGS_SHUTDOWN);
+ info->paused = !!(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED);
+ info->blocked = !!(op.u.getdomaininfo.flags & DOMFLAGS_BLOCKED);
+ info->running = !!(op.u.getdomaininfo.flags & DOMFLAGS_RUNNING);
+
+ info->shutdown_reason =
+ (op.u.getdomaininfo.flags>>DOMFLAGS_SHUTDOWNSHIFT) &
+ DOMFLAGS_SHUTDOWNMASK;
+
+ info->nr_pages = op.u.getdomaininfo.tot_pages;
+ info->max_memkb = op.u.getdomaininfo.max_pages<<(PAGE_SHIFT-10);
+ info->shared_info_frame = op.u.getdomaininfo.shared_info_frame;
+ info->cpu_time = op.u.getdomaininfo.cpu_time;
+ strncpy(info->name, op.u.getdomaininfo.name, XC_DOMINFO_MAXNAME);
+ info->name[XC_DOMINFO_MAXNAME-1] = '\0';
+
+ next_domid = (u32)op.u.getdomaininfo.domain + 1;
+ info++;
+ }
+
+ return nr_doms;
+}
+
+int xc_domain_getfullinfo(int xc_handle,
+ u32 domid,
+ dom0_op_t *op,
+ full_execution_context_t *ctxt )
+{
+ int rc;
+ op->cmd = DOM0_GETDOMAININFO;
+ op->u.getdomaininfo.domain = (domid_t)domid;
+ op->u.getdomaininfo.ctxt = ctxt;
+
+ rc = do_dom0_op(xc_handle, op);
+ if ( ((u32)op->u.getdomaininfo.domain != domid) && rc > 0 )
+ return -ESRCH;
+ else
+ return rc;
+}
+
+
+int xc_shadow_control(int xc_handle,
+ u32 domid,
+ unsigned int sop,
+ unsigned long *dirty_bitmap,
+ unsigned long pages,
+ xc_shadow_control_stats_t *stats )
+{
+ int rc;
+ dom0_op_t op;
+ op.cmd = DOM0_SHADOW_CONTROL;
+ op.u.shadow_control.domain = (domid_t)domid;
+ op.u.shadow_control.op = sop;
+ op.u.shadow_control.dirty_bitmap = dirty_bitmap;
+ op.u.shadow_control.pages = pages;
+
+ rc = do_dom0_op(xc_handle, &op);
+
+ if ( stats )
+ memcpy(stats, &op.u.shadow_control.stats,
+ sizeof(xc_shadow_control_stats_t));
+
+ return (rc == 0) ? op.u.shadow_control.pages : rc;
+}
+
+int xc_domain_setname(int xc_handle,
+ u32 domid,
+ char *name)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_SETDOMAINNAME;
+ op.u.setdomainname.domain = (domid_t)domid;
+ strncpy(op.u.setdomainname.name, name, MAX_DOMAIN_NAME);
+ return do_dom0_op(xc_handle, &op);
+}
+
+int xc_domain_setinitialmem(int xc_handle,
+ u32 domid,
+ unsigned int initial_memkb)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_SETDOMAININITIALMEM;
+ op.u.setdomaininitialmem.domain = (domid_t)domid;
+ op.u.setdomaininitialmem.initial_memkb = initial_memkb;
+ return do_dom0_op(xc_handle, &op);
+}
+
+int xc_domain_setmaxmem(int xc_handle,
+ u32 domid,
+ unsigned int max_memkb)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_SETDOMAINMAXMEM;
+ op.u.setdomainmaxmem.domain = (domid_t)domid;
+ op.u.setdomainmaxmem.max_memkb = max_memkb;
+ return do_dom0_op(xc_handle, &op);
+}
+
--- /dev/null
+/*
+ * Copyright (c) 1995, 1996 Erik Theisen. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+typedef u_int8_t Elf_Byte;
+
+typedef u_int32_t Elf32_Addr; /* Unsigned program address */
+typedef u_int32_t Elf32_Off; /* Unsigned file offset */
+typedef int32_t Elf32_Sword; /* Signed large integer */
+typedef u_int32_t Elf32_Word; /* Unsigned large integer */
+typedef u_int16_t Elf32_Half; /* Unsigned medium integer */
+
+typedef u_int64_t Elf64_Addr;
+typedef u_int64_t Elf64_Off;
+typedef int32_t Elf64_Shalf;
+
+typedef int32_t Elf64_Sword;
+typedef u_int32_t Elf64_Word;
+
+typedef int64_t Elf64_Sxword;
+typedef u_int64_t Elf64_Xword;
+
+typedef u_int32_t Elf64_Half;
+typedef u_int16_t Elf64_Quarter;
+
+/*
+ * e_ident[] identification indexes
+ * See http://www.caldera.com/developers/gabi/2000-07-17/ch4.eheader.html
+ */
+#define EI_MAG0 0 /* file ID */
+#define EI_MAG1 1 /* file ID */
+#define EI_MAG2 2 /* file ID */
+#define EI_MAG3 3 /* file ID */
+#define EI_CLASS 4 /* file class */
+#define EI_DATA 5 /* data encoding */
+#define EI_VERSION 6 /* ELF header version */
+#define EI_OSABI 7 /* OS/ABI ID */
+#define EI_ABIVERSION 8 /* ABI version */
+#define EI_PAD 9 /* start of pad bytes */
+#define EI_NIDENT 16 /* Size of e_ident[] */
+
+/* e_ident[] magic number */
+#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */
+#define ELFMAG1 'E' /* e_ident[EI_MAG1] */
+#define ELFMAG2 'L' /* e_ident[EI_MAG2] */
+#define ELFMAG3 'F' /* e_ident[EI_MAG3] */
+#define ELFMAG "\177ELF" /* magic */
+#define SELFMAG 4 /* size of magic */
+
+/* e_ident[] file class */
+#define ELFCLASSNONE 0 /* invalid */
+#define ELFCLASS32 1 /* 32-bit objs */
+#define ELFCLASS64 2 /* 64-bit objs */
+#define ELFCLASSNUM 3 /* number of classes */
+
+/* e_ident[] data encoding */
+#define ELFDATANONE 0 /* invalid */
+#define ELFDATA2LSB 1 /* Little-Endian */
+#define ELFDATA2MSB 2 /* Big-Endian */
+#define ELFDATANUM 3 /* number of data encode defines */
+
+/* e_ident[] Operating System/ABI */
+#define ELFOSABI_SYSV 0 /* UNIX System V ABI */
+#define ELFOSABI_HPUX 1 /* HP-UX operating system */
+#define ELFOSABI_NETBSD 2 /* NetBSD */
+#define ELFOSABI_LINUX 3 /* GNU/Linux */
+#define ELFOSABI_HURD 4 /* GNU/Hurd */
+#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */
+#define ELFOSABI_SOLARIS 6 /* Solaris */
+#define ELFOSABI_MONTEREY 7 /* Monterey */
+#define ELFOSABI_IRIX 8 /* IRIX */
+#define ELFOSABI_FREEBSD 9 /* FreeBSD */
+#define ELFOSABI_TRU64 10 /* TRU64 UNIX */
+#define ELFOSABI_MODESTO 11 /* Novell Modesto */
+#define ELFOSABI_OPENBSD 12 /* OpenBSD */
+#define ELFOSABI_ARM 97 /* ARM */
+#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
+
+/* e_ident */
+#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
+ (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
+ (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
+ (ehdr).e_ident[EI_MAG3] == ELFMAG3)
+
+/* ELF Header */
+typedef struct elfhdr {
+ unsigned char e_ident[EI_NIDENT]; /* ELF Identification */
+ Elf32_Half e_type; /* object file type */
+ Elf32_Half e_machine; /* machine */
+ Elf32_Word e_version; /* object file version */
+ Elf32_Addr e_entry; /* virtual entry point */
+ Elf32_Off e_phoff; /* program header table offset */
+ Elf32_Off e_shoff; /* section header table offset */
+ Elf32_Word e_flags; /* processor-specific flags */
+ Elf32_Half e_ehsize; /* ELF header size */
+ Elf32_Half e_phentsize; /* program header entry size */
+ Elf32_Half e_phnum; /* number of program header entries */
+ Elf32_Half e_shentsize; /* section header entry size */
+ Elf32_Half e_shnum; /* number of section header entries */
+ Elf32_Half e_shstrndx; /* section header table's "section
+ header string table" entry offset */
+} Elf32_Ehdr;
+
+typedef struct {
+ unsigned char e_ident[EI_NIDENT]; /* Id bytes */
+ Elf64_Quarter e_type; /* file type */
+ Elf64_Quarter e_machine; /* machine type */
+ Elf64_Half e_version; /* version number */
+ Elf64_Addr e_entry; /* entry point */
+ Elf64_Off e_phoff; /* Program hdr offset */
+ Elf64_Off e_shoff; /* Section hdr offset */
+ Elf64_Half e_flags; /* Processor flags */
+ Elf64_Quarter e_ehsize; /* sizeof ehdr */
+ Elf64_Quarter e_phentsize; /* Program header entry size */
+ Elf64_Quarter e_phnum; /* Number of program headers */
+ Elf64_Quarter e_shentsize; /* Section header entry size */
+ Elf64_Quarter e_shnum; /* Number of section headers */
+ Elf64_Quarter e_shstrndx; /* String table index */
+} Elf64_Ehdr;
+
+/* e_type */
+#define ET_NONE 0 /* No file type */
+#define ET_REL 1 /* relocatable file */
+#define ET_EXEC 2 /* executable file */
+#define ET_DYN 3 /* shared object file */
+#define ET_CORE 4 /* core file */
+#define ET_NUM 5 /* number of types */
+#define ET_LOPROC 0xff00 /* reserved range for processor */
+#define ET_HIPROC 0xffff /* specific e_type */
+
+/* e_machine */
+#define EM_NONE 0 /* No Machine */
+#define EM_M32 1 /* AT&T WE 32100 */
+#define EM_SPARC 2 /* SPARC */
+#define EM_386 3 /* Intel 80386 */
+#define EM_68K 4 /* Motorola 68000 */
+#define EM_88K 5 /* Motorola 88000 */
+#define EM_486 6 /* Intel 80486 - unused? */
+#define EM_860 7 /* Intel 80860 */
+#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */
+/*
+ * Don't know if EM_MIPS_RS4_BE,
+ * EM_SPARC64, EM_PARISC,
+ * or EM_PPC are ABI compliant
+ */
+#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */
+#define EM_SPARC64 11 /* SPARC v9 64-bit unoffical */
+#define EM_PARISC 15 /* HPPA */
+#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */
+#define EM_PPC 20 /* PowerPC */
+#define EM_ARM 40 /* Advanced RISC Machines ARM */
+#define EM_ALPHA 41 /* DEC ALPHA */
+#define EM_SPARCV9 43 /* SPARC version 9 */
+#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */
+#define EM_X86_64 62 /* AMD x86-64 architecture */
+#define EM_VAX 75 /* DEC VAX */
+#define EM_NUM 15 /* number of machine types */
+
+/* Version */
+#define EV_NONE 0 /* Invalid */
+#define EV_CURRENT 1 /* Current */
+#define EV_NUM 2 /* number of versions */
+
+/* Section Header */
+typedef struct {
+ Elf32_Word sh_name; /* name - index into section header
+ string table section */
+ Elf32_Word sh_type; /* type */
+ Elf32_Word sh_flags; /* flags */
+ Elf32_Addr sh_addr; /* address */
+ Elf32_Off sh_offset; /* file offset */
+ Elf32_Word sh_size; /* section size */
+ Elf32_Word sh_link; /* section header table index link */
+ Elf32_Word sh_info; /* extra information */
+ Elf32_Word sh_addralign; /* address alignment */
+ Elf32_Word sh_entsize; /* section entry size */
+} Elf32_Shdr;
+
+typedef struct {
+ Elf64_Half sh_name; /* section name */
+ Elf64_Half sh_type; /* section type */
+ Elf64_Xword sh_flags; /* section flags */
+ Elf64_Addr sh_addr; /* virtual address */
+ Elf64_Off sh_offset; /* file offset */
+ Elf64_Xword sh_size; /* section size */
+ Elf64_Half sh_link; /* link to another */
+ Elf64_Half sh_info; /* misc info */
+ Elf64_Xword sh_addralign; /* memory alignment */
+ Elf64_Xword sh_entsize; /* table entry size */
+} Elf64_Shdr;
+
+/* Special Section Indexes */
+#define SHN_UNDEF 0 /* undefined */
+#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */
+#define SHN_LOPROC 0xff00 /* reserved range for processor */
+#define SHN_HIPROC 0xff1f /* specific section indexes */
+#define SHN_ABS 0xfff1 /* absolute value */
+#define SHN_COMMON 0xfff2 /* common symbol */
+#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */
+
+/* sh_type */
+#define SHT_NULL 0 /* inactive */
+#define SHT_PROGBITS 1 /* program defined information */
+#define SHT_SYMTAB 2 /* symbol table section */
+#define SHT_STRTAB 3 /* string table section */
+#define SHT_RELA 4 /* relocation section with addends*/
+#define SHT_HASH 5 /* symbol hash table section */
+#define SHT_DYNAMIC 6 /* dynamic section */
+#define SHT_NOTE 7 /* note section */
+#define SHT_NOBITS 8 /* no space section */
+#define SHT_REL 9 /* relation section without addends */
+#define SHT_SHLIB 10 /* reserved - purpose unknown */
+#define SHT_DYNSYM 11 /* dynamic symbol table section */
+#define SHT_NUM 12 /* number of section types */
+#define SHT_LOPROC 0x70000000 /* reserved range for processor */
+#define SHT_HIPROC 0x7fffffff /* specific section header types */
+#define SHT_LOUSER 0x80000000 /* reserved range for application */
+#define SHT_HIUSER 0xffffffff /* specific indexes */
+
+/* Section names */
+#define ELF_BSS ".bss" /* uninitialized data */
+#define ELF_DATA ".data" /* initialized data */
+#define ELF_DEBUG ".debug" /* debug */
+#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */
+#define ELF_DYNSTR ".dynstr" /* dynamic string table */
+#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */
+#define ELF_FINI ".fini" /* termination code */
+#define ELF_GOT ".got" /* global offset table */
+#define ELF_HASH ".hash" /* symbol hash table */
+#define ELF_INIT ".init" /* initialization code */
+#define ELF_REL_DATA ".rel.data" /* relocation data */
+#define ELF_REL_FINI ".rel.fini" /* relocation termination code */
+#define ELF_REL_INIT ".rel.init" /* relocation initialization code */
+#define ELF_REL_DYN ".rel.dyn" /* relocaltion dynamic link info */
+#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */
+#define ELF_REL_TEXT ".rel.text" /* relocation code */
+#define ELF_RODATA ".rodata" /* read-only data */
+#define ELF_SHSTRTAB ".shstrtab" /* section header string table */
+#define ELF_STRTAB ".strtab" /* string table */
+#define ELF_SYMTAB ".symtab" /* symbol table */
+#define ELF_TEXT ".text" /* code */
+
+
+/* Section Attribute Flags - sh_flags */
+#define SHF_WRITE 0x1 /* Writable */
+#define SHF_ALLOC 0x2 /* occupies memory */
+#define SHF_EXECINSTR 0x4 /* executable */
+#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor */
+ /* specific section attributes */
+
+/* Symbol Table Entry */
+typedef struct elf32_sym {
+ Elf32_Word st_name; /* name - index into string table */
+ Elf32_Addr st_value; /* symbol value */
+ Elf32_Word st_size; /* symbol size */
+ unsigned char st_info; /* type and binding */
+ unsigned char st_other; /* 0 - no defined meaning */
+ Elf32_Half st_shndx; /* section header index */
+} Elf32_Sym;
+
+typedef struct {
+ Elf64_Half st_name; /* Symbol name index in str table */
+ Elf_Byte st_info; /* type / binding attrs */
+ Elf_Byte st_other; /* unused */
+ Elf64_Quarter st_shndx; /* section index of symbol */
+ Elf64_Xword st_value; /* value of symbol */
+ Elf64_Xword st_size; /* size of symbol */
+} Elf64_Sym;
+
+/* Symbol table index */
+#define STN_UNDEF 0 /* undefined */
+
+/* Extract symbol info - st_info */
+#define ELF32_ST_BIND(x) ((x) >> 4)
+#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf)
+#define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf))
+
+#define ELF64_ST_BIND(x) ((x) >> 4)
+#define ELF64_ST_TYPE(x) (((unsigned int) x) & 0xf)
+#define ELF64_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf))
+
+/* Symbol Binding - ELF32_ST_BIND - st_info */
+#define STB_LOCAL 0 /* Local symbol */
+#define STB_GLOBAL 1 /* Global symbol */
+#define STB_WEAK 2 /* like global - lower precedence */
+#define STB_NUM 3 /* number of symbol bindings */
+#define STB_LOPROC 13 /* reserved range for processor */
+#define STB_HIPROC 15 /* specific symbol bindings */
+
+/* Symbol type - ELF32_ST_TYPE - st_info */
+#define STT_NOTYPE 0 /* not specified */
+#define STT_OBJECT 1 /* data object */
+#define STT_FUNC 2 /* function */
+#define STT_SECTION 3 /* section */
+#define STT_FILE 4 /* file */
+#define STT_NUM 5 /* number of symbol types */
+#define STT_LOPROC 13 /* reserved range for processor */
+#define STT_HIPROC 15 /* specific symbol types */
+
+/* Relocation entry with implicit addend */
+typedef struct {
+ Elf32_Addr r_offset; /* offset of relocation */
+ Elf32_Word r_info; /* symbol table index and type */
+} Elf32_Rel;
+
+/* Relocation entry with explicit addend */
+typedef struct {
+ Elf32_Addr r_offset; /* offset of relocation */
+ Elf32_Word r_info; /* symbol table index and type */
+ Elf32_Sword r_addend;
+} Elf32_Rela;
+
+/* Extract relocation info - r_info */
+#define ELF32_R_SYM(i) ((i) >> 8)
+#define ELF32_R_TYPE(i) ((unsigned char) (i))
+#define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t))
+
+typedef struct {
+ Elf64_Xword r_offset; /* where to do it */
+ Elf64_Xword r_info; /* index & type of relocation */
+} Elf64_Rel;
+
+typedef struct {
+ Elf64_Xword r_offset; /* where to do it */
+ Elf64_Xword r_info; /* index & type of relocation */
+ Elf64_Sxword r_addend; /* adjustment value */
+} Elf64_Rela;
+
+#define ELF64_R_SYM(info) ((info) >> 32)
+#define ELF64_R_TYPE(info) ((info) & 0xFFFFFFFF)
+#define ELF64_R_INFO(s,t) (((s) << 32) + (u_int32_t)(t))
+
+/* Program Header */
+typedef struct {
+ Elf32_Word p_type; /* segment type */
+ Elf32_Off p_offset; /* segment offset */
+ Elf32_Addr p_vaddr; /* virtual address of segment */
+ Elf32_Addr p_paddr; /* physical address - ignored? */
+ Elf32_Word p_filesz; /* number of bytes in file for seg. */
+ Elf32_Word p_memsz; /* number of bytes in mem. for seg. */
+ Elf32_Word p_flags; /* flags */
+ Elf32_Word p_align; /* memory alignment */
+} Elf32_Phdr;
+
+typedef struct {
+ Elf64_Half p_type; /* entry type */
+ Elf64_Half p_flags; /* flags */
+ Elf64_Off p_offset; /* offset */
+ Elf64_Addr p_vaddr; /* virtual address */
+ Elf64_Addr p_paddr; /* physical address */
+ Elf64_Xword p_filesz; /* file size */
+ Elf64_Xword p_memsz; /* memory size */
+ Elf64_Xword p_align; /* memory & file alignment */
+} Elf64_Phdr;
+
+/* Segment types - p_type */
+#define PT_NULL 0 /* unused */
+#define PT_LOAD 1 /* loadable segment */
+#define PT_DYNAMIC 2 /* dynamic linking section */
+#define PT_INTERP 3 /* the RTLD */
+#define PT_NOTE 4 /* auxiliary information */
+#define PT_SHLIB 5 /* reserved - purpose undefined */
+#define PT_PHDR 6 /* program header */
+#define PT_NUM 7 /* Number of segment types */
+#define PT_LOPROC 0x70000000 /* reserved range for processor */
+#define PT_HIPROC 0x7fffffff /* specific segment types */
+
+/* Segment flags - p_flags */
+#define PF_X 0x1 /* Executable */
+#define PF_W 0x2 /* Writable */
+#define PF_R 0x4 /* Readable */
+#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */
+ /* specific segment flags */
+
+/* Dynamic structure */
+typedef struct {
+ Elf32_Sword d_tag; /* controls meaning of d_val */
+ union {
+ Elf32_Word d_val; /* Multiple meanings - see d_tag */
+ Elf32_Addr d_ptr; /* program virtual address */
+ } d_un;
+} Elf32_Dyn;
+
+typedef struct {
+ Elf64_Xword d_tag; /* controls meaning of d_val */
+ union {
+ Elf64_Addr d_ptr;
+ Elf64_Xword d_val;
+ } d_un;
+} Elf64_Dyn;
+
+/* Dynamic Array Tags - d_tag */
+#define DT_NULL 0 /* marks end of _DYNAMIC array */
+#define DT_NEEDED 1 /* string table offset of needed lib */
+#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */
+#define DT_PLTGOT 3 /* address PLT/GOT */
+#define DT_HASH 4 /* address of symbol hash table */
+#define DT_STRTAB 5 /* address of string table */
+#define DT_SYMTAB 6 /* address of symbol table */
+#define DT_RELA 7 /* address of relocation table */
+#define DT_RELASZ 8 /* size of relocation table */
+#define DT_RELAENT 9 /* size of relocation entry */
+#define DT_STRSZ 10 /* size of string table */
+#define DT_SYMENT 11 /* size of symbol table entry */
+#define DT_INIT 12 /* address of initialization func. */
+#define DT_FINI 13 /* address of termination function */
+#define DT_SONAME 14 /* string table offset of shared obj */
+#define DT_RPATH 15 /* string table offset of library
+ search path */
+#define DT_SYMBOLIC 16 /* start sym search in shared obj. */
+#define DT_REL 17 /* address of rel. tbl. w addends */
+#define DT_RELSZ 18 /* size of DT_REL relocation table */
+#define DT_RELENT 19 /* size of DT_REL relocation entry */
+#define DT_PLTREL 20 /* PLT referenced relocation entry */
+#define DT_DEBUG 21 /* bugger */
+#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */
+#define DT_JMPREL 23 /* add. of PLT's relocation entries */
+#define DT_BIND_NOW 24 /* Bind now regardless of env setting */
+#define DT_NUM 25 /* Number used. */
+#define DT_LOPROC 0x70000000 /* reserved range for processor */
+#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */
+
+/* Standard ELF hashing function */
+unsigned int elf_hash(const unsigned char *name);
+
+/*
+ * Note Definitions
+ */
+typedef struct {
+ Elf32_Word namesz;
+ Elf32_Word descsz;
+ Elf32_Word type;
+} Elf32_Note;
+
+typedef struct {
+ Elf64_Half namesz;
+ Elf64_Half descsz;
+ Elf64_Half type;
+} Elf64_Note;
+
+
+#if defined(ELFSIZE)
+#define CONCAT(x,y) __CONCAT(x,y)
+#define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x)))
+#define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y))))
+#define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE))
+#define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x)))
+#endif
+
+#if defined(ELFSIZE) && (ELFSIZE == 32)
+#define Elf_Ehdr Elf32_Ehdr
+#define Elf_Phdr Elf32_Phdr
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Sym Elf32_Sym
+#define Elf_Rel Elf32_Rel
+#define Elf_RelA Elf32_Rela
+#define Elf_Dyn Elf32_Dyn
+#define Elf_Word Elf32_Word
+#define Elf_Sword Elf32_Sword
+#define Elf_Addr Elf32_Addr
+#define Elf_Off Elf32_Off
+#define Elf_Nhdr Elf32_Nhdr
+#define Elf_Note Elf32_Note
+
+#define ELF_R_SYM ELF32_R_SYM
+#define ELF_R_TYPE ELF32_R_TYPE
+#define ELF_R_INFO ELF32_R_INFO
+#define ELFCLASS ELFCLASS32
+
+#define ELF_ST_BIND ELF32_ST_BIND
+#define ELF_ST_TYPE ELF32_ST_TYPE
+#define ELF_ST_INFO ELF32_ST_INFO
+
+#define AuxInfo Aux32Info
+#elif defined(ELFSIZE) && (ELFSIZE == 64)
+#define Elf_Ehdr Elf64_Ehdr
+#define Elf_Phdr Elf64_Phdr
+#define Elf_Shdr Elf64_Shdr
+#define Elf_Sym Elf64_Sym
+#define Elf_Rel Elf64_Rel
+#define Elf_RelA Elf64_Rela
+#define Elf_Dyn Elf64_Dyn
+#define Elf_Word Elf64_Word
+#define Elf_Sword Elf64_Sword
+#define Elf_Addr Elf64_Addr
+#define Elf_Off Elf64_Off
+#define Elf_Nhdr Elf64_Nhdr
+#define Elf_Note Elf64_Note
+
+#define ELF_R_SYM ELF64_R_SYM
+#define ELF_R_TYPE ELF64_R_TYPE
+#define ELF_R_INFO ELF64_R_INFO
+#define ELFCLASS ELFCLASS64
+
+#define ELF_ST_BIND ELF64_ST_BIND
+#define ELF_ST_TYPE ELF64_ST_TYPE
+#define ELF_ST_INFO ELF64_ST_INFO
+
+#define AuxInfo Aux64Info
+#endif
+
--- /dev/null
+/******************************************************************************
+ * xc_evtchn.c
+ *
+ * API for manipulating and accessing inter-domain event channels.
+ *
+ * Copyright (c) 2004, K A Fraser.
+ */
+
+#include "xc_private.h"
+
+
+static int do_evtchn_op(int xc_handle, evtchn_op_t *op)
+{
+ int ret = -1;
+ privcmd_hypercall_t hypercall;
+
+ hypercall.op = __HYPERVISOR_event_channel_op;
+ hypercall.arg[0] = (unsigned long)op;
+
+ if ( mlock(op, sizeof(*op)) != 0 )
+ {
+ PERROR("Could not lock memory for Xen hypercall");
+ goto out1;
+ }
+
+ if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
+ goto out2;
+
+ out2: (void)munlock(op, sizeof(*op));
+ out1: return ret;
+}
+
+
+int xc_evtchn_bind_interdomain(int xc_handle,
+ u32 dom1,
+ u32 dom2,
+ int *port1,
+ int *port2)
+{
+ evtchn_op_t op;
+ int rc;
+
+ op.cmd = EVTCHNOP_bind_interdomain;
+ op.u.bind_interdomain.dom1 = (domid_t)dom1;
+ op.u.bind_interdomain.dom2 = (domid_t)dom2;
+
+ if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 )
+ {
+ if ( port1 != NULL )
+ *port1 = op.u.bind_interdomain.port1;
+ if ( port2 != NULL )
+ *port2 = op.u.bind_interdomain.port2;
+ }
+
+ return rc;
+}
+
+
+int xc_evtchn_bind_virq(int xc_handle,
+ int virq,
+ int *port)
+{
+ evtchn_op_t op;
+ int rc;
+
+ op.cmd = EVTCHNOP_bind_virq;
+ op.u.bind_virq.virq = (u32)virq;
+
+ if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 )
+ {
+ if ( port != NULL )
+ *port = op.u.bind_virq.port;
+ }
+
+ return rc;
+}
+
+
+int xc_evtchn_close(int xc_handle,
+ u32 dom,
+ int port)
+{
+ evtchn_op_t op;
+ op.cmd = EVTCHNOP_close;
+ op.u.close.dom = (domid_t)dom;
+ op.u.close.port = port;
+ return do_evtchn_op(xc_handle, &op);
+}
+
+
+int xc_evtchn_send(int xc_handle,
+ int local_port)
+{
+ evtchn_op_t op;
+ op.cmd = EVTCHNOP_send;
+ op.u.send.local_port = local_port;
+ return do_evtchn_op(xc_handle, &op);
+}
+
+
+int xc_evtchn_status(int xc_handle,
+ u32 dom,
+ int port,
+ xc_evtchn_status_t *status)
+{
+ evtchn_op_t op;
+ int rc;
+
+ op.cmd = EVTCHNOP_status;
+ op.u.status.dom = (domid_t)dom;
+ op.u.status.port = port;
+
+ if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 )
+ {
+ switch ( status->status = op.u.status.status )
+ {
+ case EVTCHNSTAT_interdomain:
+ status->u.interdomain.dom = (u32)op.u.status.u.interdomain.dom;
+ status->u.interdomain.port = op.u.status.u.interdomain.port;
+ break;
+ case EVTCHNSTAT_pirq:
+ status->u.pirq = op.u.status.u.pirq;
+ break;
+ case EVTCHNSTAT_virq:
+ status->u.virq = op.u.status.u.virq;
+ break;
+ }
+ }
+
+ return rc;
+}
--- /dev/null
+#include "xc_io.h"
+
+void xcio_error(XcIOContext *ctxt, const char *msg, ...){
+ va_list args;
+
+ va_start(args, msg);
+ vfprintf(stdout, msg, args); fprintf(stdout, "\n");
+ IOStream_vprint(ctxt->info, msg, args);
+ IOStream_print(ctxt->info, "\n");
+ va_end(args);
+}
+
+void xcio_info(XcIOContext *ctxt, const char *msg, ...){
+ va_list args;
+
+ if(0 && !(ctxt->flags & XCFLAGS_VERBOSE)) return;
+ va_start(args, msg);
+ vfprintf(stdout, msg, args); fprintf(stdout, "\n");
+ IOStream_vprint(ctxt->info, msg, args);
+ va_end(args);
+}
+
+void xcio_debug(XcIOContext *ctxt, const char *msg, ...){
+ va_list args;
+
+ if(0 && !(ctxt->flags & XCFLAGS_DEBUG)) return;
+ va_start(args, msg);
+ vfprintf(stdout, msg, args); fprintf(stdout, "\n");
+ IOStream_vprint(ctxt->info, msg, args);
+ va_end(args);
+}
--- /dev/null
+#ifndef __XC_XC_IO_H__
+#define __XC_XC_IO_H__
+
+#include "xc_private.h"
+#include "iostream.h"
+
+typedef struct XcIOContext {
+ u32 domain;
+ unsigned flags;
+ IOStream *io;
+ IOStream *info;
+ IOStream *err;
+ char *vmconfig;
+ int vmconfig_n;
+} XcIOContext;
+
+static inline int xcio_read(XcIOContext *ctxt, void *buf, int n){
+ int rc;
+
+ rc = IOStream_read(ctxt->io, buf, n);
+ return (rc == n ? 0 : rc);
+}
+
+static inline int xcio_write(XcIOContext *ctxt, void *buf, int n){
+ int rc;
+
+ rc = IOStream_write(ctxt->io, buf, n);
+ return (rc == n ? 0 : rc);
+}
+
+static inline int xcio_flush(XcIOContext *ctxt){
+ return IOStream_flush(ctxt->io);
+}
+
+extern void xcio_error(XcIOContext *ctxt, const char *msg, ...);
+extern void xcio_info(XcIOContext *ctxt, const char *msg, ...);
+
+#define xcio_perror(_ctxt, _msg...) \
+xcio_error(_ctxt, "(errno %d %s)" _msg, errno, strerror(errno), ## _msg)
+
+#endif /* ! __XC_XC_IO_H__ */
+
+
+
--- /dev/null
+/******************************************************************************
+ * xc_linux_build.c
+ */
+
+#include "xc_private.h"
+#define ELFSIZE 32
+#include "xc_elf.h"
+#include <zlib.h>
+
+#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
+#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+
+#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
+#define round_pgdown(_p) ((_p)&PAGE_MASK)
+
+static int readelfimage_base_and_size(char *elfbase,
+ unsigned long elfsize,
+ unsigned long *pkernstart,
+ unsigned long *pkernend,
+ unsigned long *pkernentry);
+static int loadelfimage(char *elfbase, int pmh, unsigned long *parray,
+ unsigned long vstart);
+
+static long get_tot_pages(int xc_handle, u32 domid)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_GETDOMAININFO;
+ op.u.getdomaininfo.domain = (domid_t)domid;
+ op.u.getdomaininfo.ctxt = NULL;
+ return (do_dom0_op(xc_handle, &op) < 0) ?
+ -1 : op.u.getdomaininfo.tot_pages;
+}
+
+static int get_pfn_list(int xc_handle,
+ u32 domid,
+ unsigned long *pfn_buf,
+ unsigned long max_pfns)
+{
+ dom0_op_t op;
+ int ret;
+ op.cmd = DOM0_GETMEMLIST;
+ op.u.getmemlist.domain = (domid_t)domid;
+ op.u.getmemlist.max_pfns = max_pfns;
+ op.u.getmemlist.buffer = pfn_buf;
+
+ if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
+ return -1;
+
+ ret = do_dom0_op(xc_handle, &op);
+
+ (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
+
+ return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
+}
+
+static int copy_to_domain_page(int pm_handle,
+ unsigned long dst_pfn,
+ void *src_page)
+{
+ void *vaddr = map_pfn_writeable(pm_handle, dst_pfn);
+ if ( vaddr == NULL )
+ return -1;
+ memcpy(vaddr, src_page, PAGE_SIZE);
+ unmap_pfn(pm_handle, vaddr);
+ return 0;
+}
+
+static int setup_guestos(int xc_handle,
+ u32 dom,
+ char *image, unsigned long image_size,
+ gzFile initrd_gfd, unsigned long initrd_len,
+ unsigned long nr_pages,
+ unsigned long *pvsi, unsigned long *pvke,
+ full_execution_context_t *ctxt,
+ const char *cmdline,
+ unsigned long shared_info_frame,
+ unsigned int control_evtchn,
+ unsigned long flags)
+{
+ l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
+ l2_pgentry_t *vl2tab=NULL, *vl2e=NULL;
+ unsigned long *page_array = NULL;
+ unsigned long l2tab;
+ unsigned long l1tab;
+ unsigned long count, i;
+ extended_start_info_t *start_info;
+ shared_info_t *shared_info;
+ mmu_t *mmu = NULL;
+ int pm_handle=-1, rc;
+
+ unsigned long nr_pt_pages;
+ unsigned long ppt_alloc;
+ unsigned long *physmap, *physmap_e, physmap_pfn;
+
+ unsigned long v_start;
+ unsigned long vkern_start;
+ unsigned long vkern_entry;
+ unsigned long vkern_end;
+ unsigned long vinitrd_start;
+ unsigned long vinitrd_end;
+ unsigned long vphysmap_start;
+ unsigned long vphysmap_end;
+ unsigned long vstartinfo_start;
+ unsigned long vstartinfo_end;
+ unsigned long vstack_start;
+ unsigned long vstack_end;
+ unsigned long vpt_start;
+ unsigned long vpt_end;
+ unsigned long v_end;
+
+ rc = readelfimage_base_and_size(image, image_size,
+ &vkern_start, &vkern_end, &vkern_entry);
+ if ( rc != 0 )
+ goto error_out;
+
+ /*
+ * Why do we need this? The number of page-table frames depends on the
+ * size of the bootstrap address space. But the size of the address space
+ * depends on the number of page-table frames (since each one is mapped
+ * read-only). We have a pair of simultaneous equations in two unknowns,
+ * which we solve by exhaustive search.
+ */
+ for ( nr_pt_pages = 2; ; nr_pt_pages++ )
+ {
+ v_start = vkern_start & ~((1<<22)-1);
+ vinitrd_start = round_pgup(vkern_end);
+ vinitrd_end = vinitrd_start + initrd_len;
+ vphysmap_start = round_pgup(vinitrd_end);
+ vphysmap_end = vphysmap_start + (nr_pages * sizeof(unsigned long));
+ vpt_start = round_pgup(vphysmap_end);
+ vpt_end = vpt_start + (nr_pt_pages * PAGE_SIZE);
+ vstartinfo_start = vpt_end;
+ vstartinfo_end = vstartinfo_start + PAGE_SIZE;
+ vstack_start = vstartinfo_end;
+ vstack_end = vstack_start + PAGE_SIZE;
+ v_end = (vstack_end + (1<<22)-1) & ~((1<<22)-1);
+ if ( (v_end - vstack_end) < (512 << 10) )
+ v_end += 1 << 22; /* Add extra 4MB to get >= 512kB padding. */
+ if ( (((v_end - v_start) >> L2_PAGETABLE_SHIFT) + 1) <= nr_pt_pages )
+ break;
+ }
+
+ if ( (v_end - v_start) > (nr_pages * PAGE_SIZE) )
+ {
+ printf("Initial guest OS requires too much space\n"
+ "(%luMB is greater than %luMB limit)\n",
+ (v_end-v_start)>>20, (nr_pages<<PAGE_SHIFT)>>20);
+ goto error_out;
+ }
+
+ printf("VIRTUAL MEMORY ARRANGEMENT:\n"
+ " Loaded kernel: %08lx->%08lx\n"
+ " Init. ramdisk: %08lx->%08lx\n"
+ " Phys-Mach map: %08lx->%08lx\n"
+ " Page tables: %08lx->%08lx\n"
+ " Start info: %08lx->%08lx\n"
+ " Boot stack: %08lx->%08lx\n"
+ " TOTAL: %08lx->%08lx\n",
+ vkern_start, vkern_end,
+ vinitrd_start, vinitrd_end,
+ vphysmap_start, vphysmap_end,
+ vpt_start, vpt_end,
+ vstartinfo_start, vstartinfo_end,
+ vstack_start, vstack_end,
+ v_start, v_end);
+ printf(" ENTRY ADDRESS: %08lx\n", vkern_entry);
+
+ if ( (pm_handle = init_pfn_mapper((domid_t)dom)) < 0 )
+ goto error_out;
+
+ if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
+ {
+ PERROR("Could not allocate memory");
+ goto error_out;
+ }
+
+ if ( get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages )
+ {
+ PERROR("Could not get the page frame list");
+ goto error_out;
+ }
+
+ loadelfimage(image, pm_handle, page_array, v_start);
+
+ /* Load the initial ramdisk image. */
+ if ( initrd_len != 0 )
+ {
+ for ( i = (vinitrd_start - v_start);
+ i < (vinitrd_end - v_start); i += PAGE_SIZE )
+ {
+ char page[PAGE_SIZE];
+ if ( gzread(initrd_gfd, page, PAGE_SIZE) == -1 )
+ {
+ PERROR("Error reading initrd image, could not");
+ goto error_out;
+ }
+ copy_to_domain_page(pm_handle,
+ page_array[i>>PAGE_SHIFT], page);
+ }
+ }
+
+ if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL )
+ goto error_out;
+
+ /* First allocate page for page dir. */
+ ppt_alloc = (vpt_start - v_start) >> PAGE_SHIFT;
+ l2tab = page_array[ppt_alloc++] << PAGE_SHIFT;
+ ctxt->pt_base = l2tab;
+
+ /* Initialise the page tables. */
+ if ( (vl2tab = map_pfn_writeable(pm_handle, l2tab >> PAGE_SHIFT)) == NULL )
+ goto error_out;
+ memset(vl2tab, 0, PAGE_SIZE);
+ vl2e = &vl2tab[l2_table_offset(v_start)];
+ for ( count = 0; count < ((v_end-v_start)>>PAGE_SHIFT); count++ )
+ {
+ if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
+ {
+ l1tab = page_array[ppt_alloc++] << PAGE_SHIFT;
+ if ( vl1tab != NULL )
+ unmap_pfn(pm_handle, vl1tab);
+ if ( (vl1tab = map_pfn_writeable(pm_handle,
+ l1tab >> PAGE_SHIFT)) == NULL )
+ goto error_out;
+ memset(vl1tab, 0, PAGE_SIZE);
+ vl1e = &vl1tab[l1_table_offset(v_start + (count<<PAGE_SHIFT))];
+ *vl2e++ = l1tab | L2_PROT;
+ }
+
+ *vl1e = (page_array[count] << PAGE_SHIFT) | L1_PROT;
+ if ( (count >= ((vpt_start-v_start)>>PAGE_SHIFT)) &&
+ (count < ((vpt_end -v_start)>>PAGE_SHIFT)) )
+ *vl1e &= ~_PAGE_RW;
+ vl1e++;
+ }
+ unmap_pfn(pm_handle, vl1tab);
+ unmap_pfn(pm_handle, vl2tab);
+
+ /* Write the phys->machine and machine->phys table entries. */
+ physmap_pfn = (vphysmap_start - v_start) >> PAGE_SHIFT;
+ physmap = physmap_e =
+ map_pfn_writeable(pm_handle, page_array[physmap_pfn++]);
+ for ( count = 0; count < nr_pages; count++ )
+ {
+ if ( add_mmu_update(xc_handle, mmu,
+ (page_array[count] << PAGE_SHIFT) |
+ MMU_MACHPHYS_UPDATE, count) )
+ goto error_out;
+ *physmap_e++ = page_array[count];
+ if ( ((unsigned long)physmap_e & (PAGE_SIZE-1)) == 0 )
+ {
+ unmap_pfn(pm_handle, physmap);
+ physmap = physmap_e =
+ map_pfn_writeable(pm_handle, page_array[physmap_pfn++]);
+ }
+ }
+ unmap_pfn(pm_handle, physmap);
+
+ /*
+ * Pin down l2tab addr as page dir page - causes hypervisor to provide
+ * correct protection for the page
+ */
+ if ( add_mmu_update(xc_handle, mmu,
+ l2tab | MMU_EXTENDED_COMMAND, MMUEXT_PIN_L2_TABLE) )
+ goto error_out;
+
+ start_info = map_pfn_writeable(
+ pm_handle, page_array[(vstartinfo_start-v_start)>>PAGE_SHIFT]);
+ memset(start_info, 0, sizeof(*start_info));
+ start_info->nr_pages = nr_pages;
+ start_info->shared_info = shared_info_frame << PAGE_SHIFT;
+ start_info->flags = flags;
+ start_info->pt_base = vpt_start;
+ start_info->nr_pt_frames = nr_pt_pages;
+ start_info->mfn_list = vphysmap_start;
+ start_info->domain_controller_evtchn = control_evtchn;
+ if ( initrd_len != 0 )
+ {
+ start_info->mod_start = vinitrd_start;
+ start_info->mod_len = initrd_len;
+ }
+ strncpy(start_info->cmd_line, cmdline, MAX_CMDLINE);
+ start_info->cmd_line[MAX_CMDLINE-1] = '\0';
+ unmap_pfn(pm_handle, start_info);
+
+ /* shared_info page starts its life empty. */
+ shared_info = map_pfn_writeable(pm_handle, shared_info_frame);
+ memset(shared_info, 0, sizeof(shared_info_t));
+ /* Mask all upcalls... */
+ for ( i = 0; i < MAX_VIRT_CPUS; i++ )
+ shared_info->vcpu_data[i].evtchn_upcall_mask = 1;
+ unmap_pfn(pm_handle, shared_info);
+
+ /* Send the page update requests down to the hypervisor. */
+ if ( finish_mmu_updates(xc_handle, mmu) )
+ goto error_out;
+
+ free(mmu);
+ (void)close_pfn_mapper(pm_handle);
+ free(page_array);
+
+ *pvsi = vstartinfo_start;
+ *pvke = vkern_entry;
+
+ return 0;
+
+ error_out:
+ if ( mmu != NULL )
+ free(mmu);
+ if ( pm_handle >= 0 )
+ (void)close_pfn_mapper(pm_handle);
+ if ( page_array != NULL )
+ free(page_array);
+ return -1;
+}
+
+static unsigned long get_filesz(int fd)
+{
+ u16 sig;
+ u32 _sz = 0;
+ unsigned long sz;
+
+ lseek(fd, 0, SEEK_SET);
+ read(fd, &sig, sizeof(sig));
+ sz = lseek(fd, 0, SEEK_END);
+ if ( sig == 0x8b1f ) /* GZIP signature? */
+ {
+ lseek(fd, -4, SEEK_END);
+ read(fd, &_sz, 4);
+ sz = _sz;
+ }
+ lseek(fd, 0, SEEK_SET);
+
+ return sz;
+}
+
+static char *read_kernel_image(const char *filename, unsigned long *size)
+{
+ int kernel_fd = -1;
+ gzFile kernel_gfd = NULL;
+ char *image = NULL;
+ unsigned int bytes;
+
+ if ( (kernel_fd = open(filename, O_RDONLY)) < 0 )
+ {
+ PERROR("Could not open kernel image");
+ goto out;
+ }
+
+ *size = get_filesz(kernel_fd);
+
+ if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
+ {
+ PERROR("Could not allocate decompression state for state file");
+ goto out;
+ }
+
+ if ( (image = malloc(*size)) == NULL )
+ {
+ PERROR("Could not allocate memory for kernel image");
+ goto out;
+ }
+
+ if ( (bytes = gzread(kernel_gfd, image, *size)) != *size )
+ {
+ PERROR("Error reading kernel image, could not"
+ " read the whole image (%d != %ld).", bytes, *size);
+ free(image);
+ image = NULL;
+ }
+
+ out:
+ if ( kernel_gfd != NULL )
+ gzclose(kernel_gfd);
+ else if ( kernel_fd >= 0 )
+ close(kernel_fd);
+ return image;
+}
+
+int xc_linux_build(int xc_handle,
+ u32 domid,
+ const char *image_name,
+ const char *ramdisk_name,
+ const char *cmdline,
+ unsigned int control_evtchn,
+ unsigned long flags)
+{
+ dom0_op_t launch_op, op;
+ int initrd_fd = -1;
+ gzFile initrd_gfd = NULL;
+ int rc, i;
+ full_execution_context_t st_ctxt, *ctxt = &st_ctxt;
+ unsigned long nr_pages;
+ char *image = NULL;
+ unsigned long image_size, initrd_size=0;
+ unsigned long vstartinfo_start, vkern_entry;
+
+ if ( (nr_pages = get_tot_pages(xc_handle, domid)) < 0 )
+ {
+ PERROR("Could not find total pages for domain");
+ goto error_out;
+ }
+
+ if ( (image = read_kernel_image(image_name, &image_size)) == NULL )
+ goto error_out;
+
+ if ( (ramdisk_name != NULL) && (strlen(ramdisk_name) != 0) )
+ {
+ if ( (initrd_fd = open(ramdisk_name, O_RDONLY)) < 0 )
+ {
+ PERROR("Could not open the initial ramdisk image");
+ goto error_out;
+ }
+
+ initrd_size = get_filesz(initrd_fd);
+
+ if ( (initrd_gfd = gzdopen(initrd_fd, "rb")) == NULL )
+ {
+ PERROR("Could not allocate decompression state for initrd");
+ goto error_out;
+ }
+ }
+
+ if ( mlock(&st_ctxt, sizeof(st_ctxt) ) )
+ {
+ PERROR("Unable to mlock ctxt");
+ return 1;
+ }
+
+ op.cmd = DOM0_GETDOMAININFO;
+ op.u.getdomaininfo.domain = (domid_t)domid;
+ op.u.getdomaininfo.ctxt = ctxt;
+ if ( (do_dom0_op(xc_handle, &op) < 0) ||
+ ((u32)op.u.getdomaininfo.domain != domid) )
+ {
+ PERROR("Could not get info on domain");
+ goto error_out;
+ }
+ if ( !(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED) ||
+ (ctxt->pt_base != 0) )
+ {
+ ERROR("Domain is already constructed");
+ goto error_out;
+ }
+
+ if ( setup_guestos(xc_handle, domid, image, image_size,
+ initrd_gfd, initrd_size, nr_pages,
+ &vstartinfo_start, &vkern_entry,
+ ctxt, cmdline,
+ op.u.getdomaininfo.shared_info_frame,
+ control_evtchn, flags) < 0 )
+ {
+ ERROR("Error constructing guest OS");
+ goto error_out;
+ }
+
+ if ( initrd_fd >= 0 )
+ close(initrd_fd);
+ if ( initrd_gfd )
+ gzclose(initrd_gfd);
+ if ( image != NULL )
+ free(image);
+
+ ctxt->flags = 0;
+
+ /*
+ * Initial register values:
+ * DS,ES,FS,GS = FLAT_GUESTOS_DS
+ * CS:EIP = FLAT_GUESTOS_CS:start_pc
+ * SS:ESP = FLAT_GUESTOS_DS:start_stack
+ * ESI = start_info
+ * [EAX,EBX,ECX,EDX,EDI,EBP are zero]
+ * EFLAGS = IF | 2 (bit 1 is reserved and should always be 1)
+ */
+ ctxt->cpu_ctxt.ds = FLAT_GUESTOS_DS;
+ ctxt->cpu_ctxt.es = FLAT_GUESTOS_DS;
+ ctxt->cpu_ctxt.fs = FLAT_GUESTOS_DS;
+ ctxt->cpu_ctxt.gs = FLAT_GUESTOS_DS;
+ ctxt->cpu_ctxt.ss = FLAT_GUESTOS_DS;
+ ctxt->cpu_ctxt.cs = FLAT_GUESTOS_CS;
+ ctxt->cpu_ctxt.eip = vkern_entry;
+ ctxt->cpu_ctxt.esp = vstartinfo_start;
+ ctxt->cpu_ctxt.esi = vstartinfo_start;
+ ctxt->cpu_ctxt.eflags = (1<<9) | (1<<2);
+
+ /* FPU is set up to default initial state. */
+ memset(ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
+
+ /* Virtual IDT is empty at start-of-day. */
+ for ( i = 0; i < 256; i++ )
+ {
+ ctxt->trap_ctxt[i].vector = i;
+ ctxt->trap_ctxt[i].cs = FLAT_GUESTOS_CS;
+ }
+ ctxt->fast_trap_idx = 0;
+
+ /* No LDT. */
+ ctxt->ldt_ents = 0;
+
+ /* Use the default Xen-provided GDT. */
+ ctxt->gdt_ents = 0;
+
+ /* Ring 1 stack is the initial stack. */
+ ctxt->guestos_ss = FLAT_GUESTOS_DS;
+ ctxt->guestos_esp = vstartinfo_start;
+
+ /* No debugging. */
+ memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
+
+ /* No callback handlers. */
+ ctxt->event_callback_cs = FLAT_GUESTOS_CS;
+ ctxt->event_callback_eip = 0;
+ ctxt->failsafe_callback_cs = FLAT_GUESTOS_CS;
+ ctxt->failsafe_callback_eip = 0;
+
+ memset( &launch_op, 0, sizeof(launch_op) );
+
+ launch_op.u.builddomain.domain = (domid_t)domid;
+ launch_op.u.builddomain.ctxt = ctxt;
+
+ launch_op.cmd = DOM0_BUILDDOMAIN;
+ rc = do_dom0_op(xc_handle, &launch_op);
+
+ return rc;
+
+ error_out:
+ if ( initrd_gfd != NULL )
+ gzclose(initrd_gfd);
+ else if ( initrd_fd >= 0 )
+ close(initrd_fd);
+ if ( image != NULL )
+ free(image);
+
+ return -1;
+}
+
+static inline int is_loadable_phdr(Elf_Phdr *phdr)
+{
+ return ((phdr->p_type == PT_LOAD) &&
+ ((phdr->p_flags & (PF_W|PF_X)) != 0));
+}
+
+static int readelfimage_base_and_size(char *elfbase,
+ unsigned long elfsize,
+ unsigned long *pkernstart,
+ unsigned long *pkernend,
+ unsigned long *pkernentry)
+{
+ Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
+ Elf_Phdr *phdr;
+ Elf_Shdr *shdr;
+ unsigned long kernstart = ~0UL, kernend=0UL;
+ char *shstrtab, *guestinfo;
+ int h;
+
+ if ( !IS_ELF(*ehdr) )
+ {
+ ERROR("Kernel image does not have an ELF header.");
+ return -EINVAL;
+ }
+
+ if ( (ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize)) > elfsize )
+ {
+ ERROR("ELF program headers extend beyond end of image.");
+ return -EINVAL;
+ }
+
+ if ( (ehdr->e_shoff + (ehdr->e_shnum * ehdr->e_shentsize)) > elfsize )
+ {
+ ERROR("ELF section headers extend beyond end of image.");
+ return -EINVAL;
+ }
+
+ /* Find the section-header strings table. */
+ if ( ehdr->e_shstrndx == SHN_UNDEF )
+ {
+ ERROR("ELF image has no section-header strings table (shstrtab).");
+ return -EINVAL;
+ }
+ shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff +
+ (ehdr->e_shstrndx*ehdr->e_shentsize));
+ shstrtab = elfbase + shdr->sh_offset;
+
+ /* Find the special '__xen_guest' section and check its contents. */
+ for ( h = 0; h < ehdr->e_shnum; h++ )
+ {
+ shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff + (h*ehdr->e_shentsize));
+ if ( strcmp(&shstrtab[shdr->sh_name], "__xen_guest") != 0 )
+ continue;
+ guestinfo = elfbase + shdr->sh_offset;
+ if ( (strstr(guestinfo, "GUEST_OS=linux") == NULL) ||
+ (strstr(guestinfo, "XEN_VER=1.3") == NULL) )
+ {
+ ERROR("Will only load Linux images built for Xen v1.3");
+ ERROR("Actually saw: '%s'", guestinfo);
+ return -EINVAL;
+ }
+ break;
+ }
+ if ( h == ehdr->e_shnum )
+ {
+ ERROR("Not a Xen-ELF image: '__xen_guest' section not found.");
+ return -EINVAL;
+ }
+
+ for ( h = 0; h < ehdr->e_phnum; h++ )
+ {
+ phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
+ if ( !is_loadable_phdr(phdr) )
+ continue;
+ if ( phdr->p_vaddr < kernstart )
+ kernstart = phdr->p_vaddr;
+ if ( (phdr->p_vaddr + phdr->p_memsz) > kernend )
+ kernend = phdr->p_vaddr + phdr->p_memsz;
+ }
+
+ if ( (kernstart > kernend) ||
+ (ehdr->e_entry < kernstart) ||
+ (ehdr->e_entry > kernend) )
+ {
+ ERROR("Malformed ELF image.");
+ return -EINVAL;
+ }
+
+ *pkernstart = kernstart;
+ *pkernend = kernend;
+ *pkernentry = ehdr->e_entry;
+
+ return 0;
+}
+
+static int loadelfimage(char *elfbase, int pmh, unsigned long *parray,
+ unsigned long vstart)
+{
+ Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
+ Elf_Phdr *phdr;
+ int h;
+
+ char *va;
+ unsigned long pa, done, chunksz;
+
+ for ( h = 0; h < ehdr->e_phnum; h++ )
+ {
+ phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
+ if ( !is_loadable_phdr(phdr) )
+ continue;
+
+ for ( done = 0; done < phdr->p_filesz; done += chunksz )
+ {
+ pa = (phdr->p_vaddr + done) - vstart;
+ va = map_pfn_writeable(pmh, parray[pa>>PAGE_SHIFT]);
+ va += pa & (PAGE_SIZE-1);
+ chunksz = phdr->p_filesz - done;
+ if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
+ chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
+ memcpy(va, elfbase + phdr->p_offset + done, chunksz);
+ unmap_pfn(pmh, va);
+ }
+
+ for ( ; done < phdr->p_memsz; done += chunksz )
+ {
+ pa = (phdr->p_vaddr + done) - vstart;
+ va = map_pfn_writeable(pmh, parray[pa>>PAGE_SHIFT]);
+ va += pa & (PAGE_SIZE-1);
+ chunksz = phdr->p_memsz - done;
+ if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
+ chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
+ memset(va, 0, chunksz);
+ unmap_pfn(pmh, va);
+ }
+ }
+
+ return 0;
+}
+
--- /dev/null
+/******************************************************************************
+ * xc_linux_restore.c
+ *
+ * Restore the state of a Linux session.
+ *
+ * Copyright (c) 2003, K A Fraser.
+ */
+
+#include "xc_private.h"
+#include <asm-xen/suspend.h>
+
+#define MAX_BATCH_SIZE 1024
+
+#define DEBUG 0
+
+#if DEBUG
+#define DPRINTF(_f, _a...) printf ( _f , ## _a )
+#else
+#define DPRINTF(_f, _a...) ((void)0)
+#endif
+
+
+static int get_pfn_list(int xc_handle,
+ u32 domain_id,
+ unsigned long *pfn_buf,
+ unsigned long max_pfns)
+{
+ dom0_op_t op;
+ int ret;
+ op.cmd = DOM0_GETMEMLIST;
+ op.u.getmemlist.domain = (domid_t)domain_id;
+ op.u.getmemlist.max_pfns = max_pfns;
+ op.u.getmemlist.buffer = pfn_buf;
+
+ if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
+ {
+ PERROR("Could not lock pfn list buffer");
+ return -1;
+ }
+
+ ret = do_dom0_op(xc_handle, &op);
+
+ (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
+
+ return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
+}
+
+/** Read the vmconfig string from the state input.
+ * It is stored as a 4-byte count 'n' followed by n bytes.
+ * The config data is stored in a new string in 'ioctxt->vmconfig',
+ * and is null-terminated. The count is stored in 'ioctxt->vmconfig_n'.
+ *
+ * @param ioctxt i/o context
+ * @return 0 on success, non-zero on error.
+ */
+static int read_vmconfig(XcIOContext *ioctxt){
+ int err = -1;
+ if(xcio_read(ioctxt, &ioctxt->vmconfig_n, sizeof(ioctxt->vmconfig_n))){
+ goto exit;
+ }
+ ioctxt->vmconfig = malloc(ioctxt->vmconfig_n + 1);
+ if(!ioctxt->vmconfig) goto exit;
+ if(xcio_read(ioctxt, ioctxt->vmconfig, ioctxt->vmconfig_n)){
+ goto exit;
+ }
+ ioctxt->vmconfig[ioctxt->vmconfig_n] = '\0';
+ err = 0;
+ exit:
+ if(err){
+ if(ioctxt->vmconfig){
+ free(ioctxt->vmconfig);
+ }
+ ioctxt->vmconfig = NULL;
+ ioctxt->vmconfig_n = 0;
+ }
+ return err;
+}
+
+int xc_linux_restore(int xc_handle, XcIOContext *ioctxt)
+{
+ dom0_op_t op;
+ int rc = 1, i, n, k;
+ unsigned long mfn, pfn, xpfn;
+ unsigned int prev_pc, this_pc;
+ u32 dom = ioctxt->domain;
+ int verify = 0;
+
+ /* Number of page frames in use by this Linux session. */
+ unsigned long nr_pfns;
+
+ /* The new domain's shared-info frame number. */
+ unsigned long shared_info_frame;
+ unsigned char shared_info[PAGE_SIZE]; /* saved contents from file */
+
+ /* A copy of the CPU context of the guest. */
+ full_execution_context_t ctxt;
+
+ /* First 16 bytes of the state file must contain 'LinuxGuestRecord'. */
+ char signature[16];
+
+ /* A copy of the domain's name. */
+ char name[MAX_DOMAIN_NAME];
+
+ /* A table containg the type of each PFN (/not/ MFN!). */
+ unsigned long *pfn_type = NULL;
+
+ /* A table of MFNs to map in the current region */
+ unsigned long *region_mfn = NULL;
+
+ /* A temporary mapping, and a copy, of one frame of guest memory. */
+ unsigned long *ppage;
+
+ /* A copy of the pfn-to-mfn table frame list. */
+ unsigned long pfn_to_mfn_frame_list[1024];
+
+ /* A table mapping each PFN to its new MFN. */
+ unsigned long *pfn_to_mfn_table = NULL;
+
+ /* used by mapper for updating the domain's copy of the table */
+ unsigned long *live_pfn_to_mfn_table = NULL;
+
+ /* A temporary mapping of the guest's suspend record. */
+ suspend_record_t *p_srec;
+
+ char *region_base;
+
+ mmu_t *mmu = NULL;
+
+ int pm_handle = -1;
+
+ /* used by debug verify code */
+ unsigned long buf[PAGE_SIZE/sizeof(unsigned long)];
+
+ if ( mlock(&ctxt, sizeof(ctxt) ) ) {
+ /* needed for when we do the build dom0 op,
+ but might as well do early */
+ PERROR("Unable to mlock ctxt");
+ return 1;
+ }
+
+ /* Start writing out the saved-domain record. */
+ if ( xcio_read(ioctxt, signature, 16) ||
+ (memcmp(signature, "LinuxGuestRecord", 16) != 0) ) {
+ xcio_error(ioctxt, "Unrecognised state format -- no signature found");
+ goto out;
+ }
+
+ if ( xcio_read(ioctxt, name, sizeof(name)) ||
+ xcio_read(ioctxt, &nr_pfns, sizeof(unsigned long)) ||
+ xcio_read(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) ) {
+ xcio_error(ioctxt, "Error reading header");
+ goto out;
+ }
+
+ if(read_vmconfig(ioctxt)){
+ xcio_error(ioctxt, "Error writing vmconfig");
+ goto out;
+ }
+
+ for ( i = 0; i < MAX_DOMAIN_NAME; i++ ) {
+ if ( name[i] == '\0' ) break;
+ if ( name[i] & 0x80 )
+ {
+ xcio_error(ioctxt, "Random characters in domain name");
+ goto out;
+ }
+ }
+ name[MAX_DOMAIN_NAME-1] = '\0';
+
+ if ( nr_pfns > 1024*1024 ) {
+ xcio_error(ioctxt, "Invalid state file -- pfn count out of range");
+ goto out;
+ }
+
+ /* We want zeroed memory so use calloc rather than malloc. */
+ pfn_to_mfn_table = calloc(1, 4 * nr_pfns);
+ pfn_type = calloc(1, 4 * nr_pfns);
+ region_mfn = calloc(1, 4 * MAX_BATCH_SIZE);
+
+ if ( (pfn_to_mfn_table == NULL) || (pfn_type == NULL) ||
+ (region_mfn == NULL) ) {
+ errno = ENOMEM;
+ goto out;
+ }
+
+ if ( mlock(region_mfn, 4 * MAX_BATCH_SIZE ) ) {
+ xcio_error(ioctxt, "Could not mlock region_mfn");
+ goto out;
+ }
+
+ /* Set the domain's name to that from the restore file */
+ if ( xc_domain_setname( xc_handle, dom, name ) ) {
+ xcio_error(ioctxt, "Could not set domain name");
+ goto out;
+ }
+
+ /* Set the domain's initial memory allocation
+ to that from the restore file */
+
+ if ( xc_domain_setinitialmem(xc_handle, dom,
+ nr_pfns * (PAGE_SIZE / 1024)) )
+ {
+ xcio_error(ioctxt, "Could not set domain initial memory");
+ goto out;
+ }
+
+ /* Get the domain's shared-info frame. */
+ op.cmd = DOM0_GETDOMAININFO;
+ op.u.getdomaininfo.domain = (domid_t)dom;
+ op.u.getdomaininfo.ctxt = NULL;
+ if ( do_dom0_op(xc_handle, &op) < 0 ) {
+ xcio_error(ioctxt, "Could not get information on new domain");
+ goto out;
+ }
+ shared_info_frame = op.u.getdomaininfo.shared_info_frame;
+
+ if ( (pm_handle = init_pfn_mapper((domid_t)dom)) < 0 )
+ goto out;
+
+
+
+ /* Build the pfn-to-mfn table. We choose MFN ordering returned by Xen. */
+ if ( get_pfn_list(xc_handle, dom, pfn_to_mfn_table, nr_pfns) != nr_pfns ) {
+ xcio_error(ioctxt, "Did not read correct number of frame numbers for new dom");
+ goto out;
+ }
+
+ if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL ) {
+ xcio_error(ioctxt, "Could not initialise for MMU updates");
+ goto out;
+ }
+
+ xcio_info(ioctxt, "Reloading memory pages: 0%%");
+
+ /*
+ * Now simply read each saved frame into its new machine frame.
+ * We uncanonicalise page tables as we go.
+ */
+ prev_pc = 0;
+
+ n=0;
+ while(1) {
+ int j;
+ unsigned long region_pfn_type[MAX_BATCH_SIZE];
+
+ this_pc = (n * 100) / nr_pfns;
+ if ( (this_pc - prev_pc) >= 5 ) {
+ xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc);
+ prev_pc = this_pc;
+ }
+
+ if ( xcio_read(ioctxt, &j, sizeof(int)) ) {
+ xcio_error(ioctxt, "Error when reading from state file");
+ goto out;
+ }
+
+ DPRINTF("batch %d\n",j);
+
+ if ( j == -1 ) {
+ verify = 1;
+ printf("Entering page verify mode\n");
+ continue;
+ }
+
+ if ( j == 0 ) break; /* our work here is done */
+
+ if( j > MAX_BATCH_SIZE ) {
+ xcio_error(ioctxt, "Max batch size exceeded. Giving up.");
+ goto out;
+ }
+
+ if ( xcio_read(ioctxt, region_pfn_type, j*sizeof(unsigned long)) ) {
+ xcio_error(ioctxt, "Error when reading from state file");
+ goto out;
+ }
+
+ for(i=0; i<j; i++) {
+ if ( (region_pfn_type[i] & LTAB_MASK) == XTAB) {
+ region_mfn[i] = 0; /* we know map will fail, but don't care */
+ } else {
+ pfn = region_pfn_type[i] & ~LTAB_MASK;
+ region_mfn[i] = pfn_to_mfn_table[pfn];
+ }
+ }
+
+ if ( (region_base = mfn_mapper_map_batch( xc_handle, dom,
+ PROT_WRITE,
+ region_mfn,
+ j )) == 0) {
+ xcio_error(ioctxt, "map batch failed");
+ goto out;
+ }
+
+ for(i=0;i<j;i++) {
+ unsigned long *ppage;
+
+ pfn = region_pfn_type[i] & ~LTAB_MASK;
+
+ if ( (region_pfn_type[i] & LTAB_MASK) == XTAB) continue;
+
+ if (pfn>nr_pfns) {
+ xcio_error(ioctxt, "pfn out of range");
+ goto out;
+ }
+
+ region_pfn_type[i] &= LTAB_MASK;
+
+ pfn_type[pfn] = region_pfn_type[i];
+
+ mfn = pfn_to_mfn_table[pfn];
+
+ if ( verify ) {
+ ppage = (unsigned long*) buf; /* debug case */
+ } else {
+ ppage = (unsigned long*) (region_base + i*PAGE_SIZE);
+ }
+
+ if ( xcio_read(ioctxt, ppage, PAGE_SIZE) ) {
+ xcio_error(ioctxt, "Error when reading from state file");
+ goto out;
+ }
+
+ switch( region_pfn_type[i] ) {
+ case 0:
+ break;
+
+ case L1TAB:
+ {
+ for ( k = 0; k < 1024; k++ ) {
+ if ( ppage[k] & _PAGE_PRESENT ) {
+ xpfn = ppage[k] >> PAGE_SHIFT;
+
+ if ( xpfn >= nr_pfns ) {
+ xcio_error(ioctxt, "Frame number in type %lu page table is "
+ "out of range. i=%d k=%d pfn=0x%lx "
+ "nr_pfns=%lu", region_pfn_type[i]>>28, i,
+ k, xpfn, nr_pfns);
+ goto out;
+ }
+
+ ppage[k] &= (PAGE_SIZE - 1) &
+ ~(_PAGE_GLOBAL | _PAGE_PAT);
+ ppage[k] |= pfn_to_mfn_table[xpfn] << PAGE_SHIFT;
+ }
+ }
+ }
+ break;
+
+ case L2TAB:
+ {
+ for ( k = 0;
+ k < (HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT);
+ k++ ) {
+ if ( ppage[k] & _PAGE_PRESENT ) {
+ xpfn = ppage[k] >> PAGE_SHIFT;
+
+ if ( xpfn >= nr_pfns ) {
+ xcio_error(ioctxt, "Frame number in type %lu page table is "
+ "out of range. i=%d k=%d pfn=%lu nr_pfns=%lu",
+ region_pfn_type[i]>>28, i, k, xpfn, nr_pfns);
+
+ goto out;
+ }
+
+ ppage[k] &= (PAGE_SIZE - 1) &
+ ~(_PAGE_GLOBAL | _PAGE_PSE);
+ ppage[k] |= pfn_to_mfn_table[xpfn] << PAGE_SHIFT;
+ }
+ }
+ }
+ break;
+
+ default:
+ xcio_error(ioctxt, "Bogus page type %lx page table is out of range."
+ " i=%d nr_pfns=%lu", region_pfn_type[i], i, nr_pfns);
+ goto out;
+
+ } /* end of page type switch statement */
+
+ if ( verify ) {
+ int res = memcmp(buf, (region_base + i*PAGE_SIZE), PAGE_SIZE );
+ if (res) {
+ int v;
+ printf("************** pfn=%lx type=%lx gotcs=%08lx "
+ "actualcs=%08lx\n", pfn, pfn_type[pfn],
+ csum_page(region_base + i*PAGE_SIZE),
+ csum_page(buf));
+ for ( v = 0; v < 4; v++ ) {
+ unsigned long *p = (unsigned long *)
+ (region_base + i*PAGE_SIZE);
+ if ( buf[v] != p[v] )
+ printf(" %d: %08lx %08lx\n",
+ v, buf[v], p[v] );
+ }
+ }
+ }
+
+ if ( add_mmu_update(xc_handle, mmu,
+ (mfn<<PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, pfn) ) {
+ printf("machpys mfn=%ld pfn=%ld\n",mfn,pfn);
+ goto out;
+ }
+
+ } /* end of 'batch' for loop */
+
+ munmap( region_base, j*PAGE_SIZE );
+ n+=j; /* crude stats */
+ }
+
+ printf("Received all pages\n");
+
+ DPRINTF("Received all pages\n");
+
+ /*
+ * Pin page tables. Do this after writing to them as otherwise Xen
+ * will barf when doing the type-checking.
+ */
+ for ( i = 0; i < nr_pfns; i++ ) {
+ if ( pfn_type[i] == L1TAB ) {
+ if ( add_mmu_update(xc_handle, mmu,
+ (pfn_to_mfn_table[i]<<PAGE_SHIFT) |
+ MMU_EXTENDED_COMMAND,
+ MMUEXT_PIN_L1_TABLE) ) {
+ printf("ERR pin L1 pfn=%lx mfn=%lx\n",
+ (unsigned long)i, pfn_to_mfn_table[i]);
+ goto out;
+ }
+ } else if ( pfn_type[i] == L2TAB ) {
+ if ( add_mmu_update(xc_handle, mmu,
+ (pfn_to_mfn_table[i]<<PAGE_SHIFT) |
+ MMU_EXTENDED_COMMAND,
+ MMUEXT_PIN_L2_TABLE) ) {
+ printf("ERR pin L2 pfn=%lx mfn=%lx\n",
+ (unsigned long)i, pfn_to_mfn_table[i]);
+ goto out;
+ }
+ }
+ }
+
+ if ( finish_mmu_updates(xc_handle, mmu) ) goto out;
+
+ xcio_info(ioctxt, "\b\b\b\b100%%\nMemory reloaded.\n");
+
+
+ if ( xcio_read(ioctxt, &ctxt, sizeof(ctxt)) ||
+ xcio_read(ioctxt, shared_info, PAGE_SIZE) ) {
+ xcio_error(ioctxt, "Error when reading from state file");
+ goto out;
+ }
+
+ /* Uncanonicalise the suspend-record frame number and poke resume rec. */
+ pfn = ctxt.cpu_ctxt.esi;
+ if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) )
+ {
+ xcio_error(ioctxt, "Suspend record frame number is bad");
+ goto out;
+ }
+ ctxt.cpu_ctxt.esi = mfn = pfn_to_mfn_table[pfn];
+ p_srec = map_pfn_writeable(pm_handle, mfn);
+ p_srec->resume_info.nr_pages = nr_pfns;
+ p_srec->resume_info.shared_info = shared_info_frame << PAGE_SHIFT;
+ p_srec->resume_info.flags = 0;
+ unmap_pfn(pm_handle, p_srec);
+
+ /* Uncanonicalise each GDT frame number. */
+ if ( ctxt.gdt_ents > 8192 ) {
+ xcio_error(ioctxt, "GDT entry count out of range");
+ goto out;
+ }
+ for ( i = 0; i < ctxt.gdt_ents; i += 512 ) {
+ pfn = ctxt.gdt_frames[i];
+ if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) ) {
+ xcio_error(ioctxt, "GDT frame number is bad");
+ goto out;
+ }
+ ctxt.gdt_frames[i] = pfn_to_mfn_table[pfn];
+ }
+
+ /* Uncanonicalise the page table base pointer. */
+ pfn = ctxt.pt_base >> PAGE_SHIFT;
+ if ( (pfn >= nr_pfns) || (pfn_type[pfn] != L2TAB) ) {
+ printf("PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx\n",
+ pfn, nr_pfns, pfn_type[pfn], (unsigned long)L2TAB);
+ xcio_error(ioctxt, "PT base is bad.");
+ goto out;
+ }
+ ctxt.pt_base = pfn_to_mfn_table[pfn] << PAGE_SHIFT;
+
+
+ /* clear any pending events and the selector */
+ memset( &(((shared_info_t *)shared_info)->evtchn_pending[0]),
+ 0, sizeof (((shared_info_t *)shared_info)->evtchn_pending)+
+ sizeof(((shared_info_t *)shared_info)->evtchn_pending_sel) );
+
+ /* Copy saved contents of shared-info page. No checking needed. */
+ ppage = map_pfn_writeable(pm_handle, shared_info_frame);
+ memcpy(ppage, shared_info, sizeof(shared_info_t));
+ unmap_pfn(pm_handle, ppage);
+
+
+ /* Uncanonicalise the pfn-to-mfn table frame-number list. */
+ for ( i = 0; i < (nr_pfns+1023)/1024; i++ ) {
+ unsigned long pfn, mfn;
+
+ pfn = pfn_to_mfn_frame_list[i];
+ if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) ) {
+ xcio_error(ioctxt, "PFN-to-MFN frame number is bad");
+ goto out;
+ }
+ mfn = pfn_to_mfn_table[pfn];
+ pfn_to_mfn_frame_list[i] = mfn;
+ }
+
+ if ( (live_pfn_to_mfn_table =
+ mfn_mapper_map_batch(xc_handle, dom,
+ PROT_WRITE,
+ pfn_to_mfn_frame_list,
+ (nr_pfns+1023)/1024 )) == 0 ) {
+ xcio_error(ioctxt, "Couldn't map pfn_to_mfn table");
+ goto out;
+ }
+
+ memcpy( live_pfn_to_mfn_table, pfn_to_mfn_table,
+ nr_pfns*sizeof(unsigned long) );
+
+ munmap( live_pfn_to_mfn_table, ((nr_pfns+1023)/1024)*PAGE_SIZE );
+
+ /*
+ * Safety checking of saved context:
+ * 1. cpu_ctxt is fine, as Xen checks that on context switch.
+ * 2. fpu_ctxt is fine, as it can't hurt Xen.
+ * 3. trap_ctxt needs the code selectors checked.
+ * 4. fast_trap_idx is checked by Xen.
+ * 5. ldt base must be page-aligned, no more than 8192 ents, ...
+ * 6. gdt already done, and further checking is done by Xen.
+ * 7. check that guestos_ss is safe.
+ * 8. pt_base is already done.
+ * 9. debugregs are checked by Xen.
+ * 10. callback code selectors need checking.
+ */
+ for ( i = 0; i < 256; i++ ) {
+ ctxt.trap_ctxt[i].vector = i;
+ if ( (ctxt.trap_ctxt[i].cs & 3) == 0 )
+ ctxt.trap_ctxt[i].cs = FLAT_GUESTOS_CS;
+ }
+ if ( (ctxt.guestos_ss & 3) == 0 ){
+ ctxt.guestos_ss = FLAT_GUESTOS_DS;
+ }
+ if ( (ctxt.event_callback_cs & 3) == 0 ){
+ ctxt.event_callback_cs = FLAT_GUESTOS_CS;
+ }
+ if ( (ctxt.failsafe_callback_cs & 3) == 0 ){
+ ctxt.failsafe_callback_cs = FLAT_GUESTOS_CS;
+ }
+ if ( ((ctxt.ldt_base & (PAGE_SIZE - 1)) != 0) ||
+ (ctxt.ldt_ents > 8192) ||
+ (ctxt.ldt_base > HYPERVISOR_VIRT_START) ||
+ ((ctxt.ldt_base + ctxt.ldt_ents*8) > HYPERVISOR_VIRT_START) )
+ {
+ xcio_error(ioctxt, "Bad LDT base or size");
+ goto out;
+ }
+
+ op.cmd = DOM0_BUILDDOMAIN;
+ op.u.builddomain.domain = (domid_t)dom;
+ op.u.builddomain.ctxt = &ctxt;
+ rc = do_dom0_op(xc_handle, &op);
+
+ /* don't start the domain as we have console etc to set up */
+
+ if( rc == 0 ) {
+ /* Success: print the domain id. */
+ xcio_info(ioctxt, "DOM=%lu\n", dom);
+ return 0;
+ }
+
+
+ out:
+ if ( (rc != 0) && (dom != 0) ){
+ xc_domain_destroy(xc_handle, dom);
+ }
+ if ( mmu != NULL ){
+ free(mmu);
+ }
+ if ( pm_handle >= 0 ){
+ (void)close_pfn_mapper(pm_handle);
+ }
+ if ( pfn_to_mfn_table != NULL ){
+ free(pfn_to_mfn_table);
+ }
+ if ( pfn_type != NULL ){
+ free(pfn_type);
+ }
+
+ if ( rc == 0 ){
+ ioctxt->domain = dom;
+ }
+ DPRINTF("Restore exit with rc=%d\n",rc);
+ return rc;
+}
--- /dev/null
+/******************************************************************************
+ * xc_linux_save.c
+ *
+ * Save the state of a running Linux session.
+ *
+ * Copyright (c) 2003, K A Fraser.
+ */
+
+#include <sys/time.h>
+#include "xc_private.h"
+#include <asm-xen/suspend.h>
+
+#define BATCH_SIZE 1024 /* 1024 pages (4MB) at a time */
+
+#define DEBUG 0
+#define DDEBUG 0
+
+#if DEBUG
+#define DPRINTF(_f, _a...) printf ( _f , ## _a )
+#else
+#define DPRINTF(_f, _a...) ((void)0)
+#endif
+
+#if DDEBUG
+#define DDPRINTF(_f, _a...) printf ( _f , ## _a )
+#else
+#define DDPRINTF(_f, _a...) ((void)0)
+#endif
+
+/*
+ * Returns TRUE if the given machine frame number has a unique mapping
+ * in the guest's pseudophysical map.
+ * 0x80000000-3 mark the shared_info, and blk/net rings
+ */
+#define MFN_IS_IN_PSEUDOPHYS_MAP(_mfn) \
+ (((_mfn) < (1024*1024)) && \
+ (((live_mfn_to_pfn_table[_mfn] < nr_pfns) && \
+ (live_pfn_to_mfn_table[live_mfn_to_pfn_table[_mfn]] == (_mfn))) || \
+ ((live_mfn_to_pfn_table[_mfn] >= 0x80000000) && \
+ (live_mfn_to_pfn_table[_mfn] <= 0x80000003)) || \
+ (live_pfn_to_mfn_table[live_mfn_to_pfn_table[_mfn]] == 0x80000004)))
+
+/* Returns TRUE if MFN is successfully converted to a PFN. */
+#define translate_mfn_to_pfn(_pmfn) \
+({ \
+ unsigned long mfn = *(_pmfn); \
+ int _res = 1; \
+ if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) ) \
+ _res = 0; \
+ else \
+ *(_pmfn) = live_mfn_to_pfn_table[mfn]; \
+ _res; \
+})
+
+static inline int test_bit ( int nr, volatile void * addr)
+{
+ return (((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] >>
+ (nr % (sizeof(unsigned long)*8))) & 1;
+}
+
+static inline void clear_bit ( int nr, volatile void * addr)
+{
+ ((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] &=
+ ~(1 << (nr % (sizeof(unsigned long)*8) ) );
+}
+
+static inline void set_bit ( int nr, volatile void * addr)
+{
+ ((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] |=
+ (1 << (nr % (sizeof(unsigned long)*8) ) );
+}
+
+/* Returns the hamming weight (i.e. the number of bits set) in a N-bit word */
+static inline unsigned int hweight32(unsigned int w)
+{
+ unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
+ res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+ res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
+ res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
+ return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
+}
+
+static inline int count_bits ( int nr, volatile void *addr)
+{
+ int i, count = 0;
+ unsigned long *p = (unsigned long *)addr;
+ /* We know that the array is padded to unsigned long. */
+ for(i=0;i<nr/(sizeof(unsigned long)*8);i++,p++)
+ count += hweight32( *p );
+ return count;
+}
+
+static inline int permute( int i, int nr, int order_nr )
+{
+ /* Need a simple permutation function so that we scan pages in a
+ pseudo random order, enabling us to get a better estimate of
+ the domain's page dirtying rate as we go (there are often
+ contiguous ranges of pfns that have similar behaviour, and we
+ want to mix them up. */
+
+ /* e.g. nr->oder 15->4 16->4 17->5 */
+ /* 512MB domain, 128k pages, order 17 */
+
+ /*
+ QPONMLKJIHGFEDCBA
+ QPONMLKJIH
+ GFEDCBA
+ */
+
+ /*
+ QPONMLKJIHGFEDCBA
+ EDCBA
+ QPONM
+ LKJIHGF
+ */
+
+ do { i = ((i>>(order_nr-10)) | ( i<<10 ) ) & ((1<<order_nr)-1); }
+ while ( i >= nr ); /* this won't ever loop if nr is a power of 2 */
+
+ return i;
+}
+
+static long long tv_to_us( struct timeval *new )
+{
+ return (new->tv_sec * 1000000) + new->tv_usec;
+}
+
+static long long llgettimeofday()
+{
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ return tv_to_us(&now);
+}
+
+static long long tv_delta( struct timeval *new, struct timeval *old )
+{
+ return ((new->tv_sec - old->tv_sec)*1000000 ) +
+ (new->tv_usec - old->tv_usec);
+}
+
+static int print_stats( int xc_handle, u32 domid,
+ int pages_sent, xc_shadow_control_stats_t *stats,
+ int print )
+{
+ static struct timeval wall_last;
+ static long long d0_cpu_last;
+ static long long d1_cpu_last;
+
+ struct timeval wall_now;
+ long long wall_delta;
+ long long d0_cpu_now, d0_cpu_delta;
+ long long d1_cpu_now, d1_cpu_delta;
+
+ gettimeofday(&wall_now, NULL);
+
+ d0_cpu_now = xc_domain_get_cpu_usage( xc_handle, 0 )/1000;
+ d1_cpu_now = xc_domain_get_cpu_usage( xc_handle, domid )/1000;
+
+ if ( (d0_cpu_now == -1) || (d1_cpu_now == -1) )
+ printf("ARRHHH!!\n");
+
+ wall_delta = tv_delta(&wall_now,&wall_last)/1000;
+
+ if ( wall_delta == 0 ) wall_delta = 1;
+
+ d0_cpu_delta = (d0_cpu_now - d0_cpu_last)/1000;
+ d1_cpu_delta = (d1_cpu_now - d1_cpu_last)/1000;
+
+ if ( print )
+ printf("delta %lldms, dom0 %d%%, target %d%%, sent %dMb/s, "
+ "dirtied %dMb/s\n",
+ wall_delta,
+ (int)((d0_cpu_delta*100)/wall_delta),
+ (int)((d1_cpu_delta*100)/wall_delta),
+ (int)((pages_sent*PAGE_SIZE*8)/(wall_delta*1000)),
+ (int)((stats->dirty_count*PAGE_SIZE*8)/(wall_delta*1000)));
+
+ d0_cpu_last = d0_cpu_now;
+ d1_cpu_last = d1_cpu_now;
+ wall_last = wall_now;
+
+ return 0;
+}
+
+/** Write the vmconfig string.
+ * It is stored as a 4-byte count 'n' followed by n bytes.
+ *
+ * @param ioctxt i/o context
+ * @return 0 on success, non-zero on error.
+ */
+static int write_vmconfig(XcIOContext *ioctxt){
+ int err = -1;
+ if(xcio_write(ioctxt, &ioctxt->vmconfig_n, sizeof(ioctxt->vmconfig_n))) goto exit;
+ if(xcio_write(ioctxt, ioctxt->vmconfig, ioctxt->vmconfig_n)) goto exit;
+ err = 0;
+ exit:
+ return err;
+}
+
+static int analysis_phase( int xc_handle, u32 domid,
+ int nr_pfns, unsigned long *arr )
+{
+ long long start, now;
+ xc_shadow_control_stats_t stats;
+
+ start = llgettimeofday();
+
+ while ( 0 )
+ {
+ int i;
+
+ xc_shadow_control( xc_handle, domid,
+ DOM0_SHADOW_CONTROL_OP_CLEAN2,
+ arr, nr_pfns, NULL);
+ printf("#Flush\n");
+ for ( i = 0; i < 100; i++ )
+ {
+ usleep(10000);
+ now = llgettimeofday();
+ xc_shadow_control( xc_handle, domid,
+ DOM0_SHADOW_CONTROL_OP_PEEK,
+ NULL, 0, &stats);
+
+ printf("now= %lld faults= %ld dirty= %ld dirty_net= %ld "
+ "dirty_block= %ld\n",
+ ((now-start)+500)/1000,
+ stats.fault_count, stats.dirty_count,
+ stats.dirty_net_count, stats.dirty_block_count);
+ }
+ }
+
+ return -1;
+}
+
+int xc_linux_save(int xc_handle, XcIOContext *ioctxt)
+{
+ dom0_op_t op;
+ int rc = 1, i, j, k, last_iter, iter = 0;
+ unsigned long mfn;
+ u32 domid = ioctxt->domain;
+ int live = (ioctxt->flags & XCFLAGS_LIVE);
+ int debug = (ioctxt->flags & XCFLAGS_DEBUG);
+ int sent_last_iter, skip_this_iter;
+
+ /* Important tuning parameters */
+ int max_iters = 29; /* limit us to 30 times round loop */
+ int max_factor = 3; /* never send more than 3x nr_pfns */
+
+ /* The new domain's shared-info frame number. */
+ unsigned long shared_info_frame;
+
+ /* A copy of the CPU context of the guest. */
+ full_execution_context_t ctxt;
+
+ /* A copy of the domain's name. */
+ char name[MAX_DOMAIN_NAME];
+
+ /* A table containg the type of each PFN (/not/ MFN!). */
+ unsigned long *pfn_type = NULL;
+ unsigned long *pfn_batch = NULL;
+
+ /* A temporary mapping, and a copy, of one frame of guest memory. */
+ unsigned long page[1024];
+
+ /* A copy of the pfn-to-mfn table frame list. */
+ unsigned long *live_pfn_to_mfn_frame_list;
+ unsigned long pfn_to_mfn_frame_list[1024];
+
+ /* Live mapping of the table mapping each PFN to its current MFN. */
+ unsigned long *live_pfn_to_mfn_table = NULL;
+ /* Live mapping of system MFN to PFN table. */
+ unsigned long *live_mfn_to_pfn_table = NULL;
+
+ /* Live mapping of shared info structure */
+ unsigned long *live_shinfo;
+
+ /* base of the region in which domain memory is mapped */
+ unsigned char *region_base = NULL;
+
+ /* A temporary mapping, and a copy, of the guest's suspend record. */
+ suspend_record_t *p_srec;
+
+ /* number of pages we're dealing with */
+ unsigned long nr_pfns;
+
+ /* power of 2 order of nr_pfns */
+ int order_nr;
+
+ /* bitmap of pages:
+ - that should be sent this iteration (unless later marked as skip);
+ - to skip this iteration because already dirty;
+ - to fixup by sending at the end if not already resent; */
+ unsigned long *to_send, *to_skip, *to_fix;
+
+ xc_shadow_control_stats_t stats;
+
+ int needed_to_fix = 0;
+ int total_sent = 0;
+
+ if (mlock(&ctxt, sizeof(ctxt))) {
+ xcio_perror(ioctxt, "Unable to mlock ctxt");
+ return 1;
+ }
+
+ /* Ensure that the domain exists, and that it is stopped. */
+ if ( xc_domain_pause(xc_handle, domid) ){
+ xcio_perror(ioctxt, "Could not pause domain");
+ goto out;
+ }
+
+ if ( xc_domain_getfullinfo( xc_handle, domid, &op, &ctxt) )
+ {
+ xcio_error(ioctxt, "Could not get full domain info");
+ goto out;
+ }
+ memcpy(name, op.u.getdomaininfo.name, sizeof(name));
+ shared_info_frame = op.u.getdomaininfo.shared_info_frame;
+
+ /* A cheesy test to see whether the domain contains valid state. */
+ if ( ctxt.pt_base == 0 ){
+ xcio_error(ioctxt, "Domain is not in a valid Linux guest OS state");
+ goto out;
+ }
+
+ /* Map the suspend-record MFN to pin it. The page must be owned by
+ domid for this to succeed. */
+ p_srec = mfn_mapper_map_single(xc_handle, domid,
+ sizeof(*p_srec), PROT_READ,
+ ctxt.cpu_ctxt.esi);
+ if (!p_srec){
+ xcio_error(ioctxt, "Couldn't map state record");
+ goto out;
+ }
+
+ nr_pfns = p_srec->nr_pfns;
+
+ /* cheesy sanity check */
+ if ( nr_pfns > 1024*1024 ){
+ xcio_error(ioctxt, "Invalid state record -- pfn count out of range: %lu", nr_pfns);
+ goto out;
+ }
+
+ /* the pfn_to_mfn_frame_list fits in a single page */
+ live_pfn_to_mfn_frame_list =
+ mfn_mapper_map_single(xc_handle, domid,
+ PAGE_SIZE, PROT_READ,
+ p_srec->pfn_to_mfn_frame_list );
+
+ if (!live_pfn_to_mfn_frame_list){
+ xcio_error(ioctxt, "Couldn't map pfn_to_mfn_frame_list");
+ goto out;
+ }
+
+ /* Track the mfn_to_pfn table down from the domains PT */
+ {
+ unsigned long *pgd;
+ unsigned long mfn_to_pfn_table_start_mfn;
+
+ pgd = mfn_mapper_map_single(xc_handle, domid,
+ PAGE_SIZE, PROT_READ,
+ ctxt.pt_base>>PAGE_SHIFT);
+
+ mfn_to_pfn_table_start_mfn =
+ pgd[HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT]>>PAGE_SHIFT;
+
+ live_mfn_to_pfn_table =
+ mfn_mapper_map_single(xc_handle, ~0UL,
+ PAGE_SIZE*1024, PROT_READ,
+ mfn_to_pfn_table_start_mfn );
+ }
+
+ /* Map all the frames of the pfn->mfn table. For migrate to succeed,
+ the guest must not change which frames are used for this purpose.
+ (its not clear why it would want to change them, and we'll be OK
+ from a safety POV anyhow. */
+
+ live_pfn_to_mfn_table = mfn_mapper_map_batch(xc_handle, domid,
+ PROT_READ,
+ live_pfn_to_mfn_frame_list,
+ (nr_pfns+1023)/1024 );
+ if( !live_pfn_to_mfn_table ){
+ xcio_perror(ioctxt, "Couldn't map pfn_to_mfn table");
+ goto out;
+ }
+
+
+ /* Canonicalise the pfn-to-mfn table frame-number list. */
+ memcpy( pfn_to_mfn_frame_list, live_pfn_to_mfn_frame_list, PAGE_SIZE );
+ for ( i = 0; i < nr_pfns; i += 1024 ){
+ if ( !translate_mfn_to_pfn(&pfn_to_mfn_frame_list[i/1024]) ){
+ xcio_error(ioctxt, "Frame # in pfn-to-mfn frame list is not in pseudophys");
+ goto out;
+ }
+ }
+
+ /* At this point, we can start the domain again if we're doing a
+ live suspend */
+
+ if( live ){
+ if ( xc_shadow_control( xc_handle, domid,
+ DOM0_SHADOW_CONTROL_OP_ENABLE_LOGDIRTY,
+ NULL, 0, NULL ) < 0 ) {
+ xcio_error(ioctxt, "Couldn't enable shadow mode");
+ goto out;
+ }
+
+ if ( xc_domain_unpause(xc_handle, domid) < 0 ){
+ xcio_error(ioctxt, "Couldn't unpause domain");
+ goto out;
+ }
+
+ last_iter = 0;
+ sent_last_iter = 1<<20; /* 4GB of pages */
+ } else{
+ last_iter = 1;
+ }
+
+ /* calculate the power of 2 order of nr_pfns, e.g.
+ 15->4 16->4 17->5 */
+ for( i=nr_pfns-1, order_nr=0; i ; i>>=1, order_nr++ );
+
+ /* Setup to_send bitmap */
+ {
+ int sz = (nr_pfns/8) + 8; /* includes slop at end of array */
+
+ to_send = malloc( sz );
+ to_fix = calloc( 1, sz );
+ to_skip = malloc( sz );
+
+ if (!to_send || !to_fix || !to_skip){
+ xcio_error(ioctxt, "Couldn't allocate to_send array");
+ goto out;
+ }
+
+ memset( to_send, 0xff, sz );
+
+ if ( mlock( to_send, sz ) ){
+ xcio_perror(ioctxt, "Unable to mlock to_send");
+ return 1;
+ }
+
+ /* (to fix is local only) */
+
+ if ( mlock( to_skip, sz ) ){
+ xcio_perror(ioctxt, "Unable to mlock to_skip");
+ return 1;
+ }
+
+ }
+
+ analysis_phase( xc_handle, domid, nr_pfns, to_skip );
+
+ /* We want zeroed memory so use calloc rather than malloc. */
+ pfn_type = calloc(BATCH_SIZE, sizeof(unsigned long));
+ pfn_batch = calloc(BATCH_SIZE, sizeof(unsigned long));
+
+ if ( (pfn_type == NULL) || (pfn_batch == NULL) ){
+ errno = ENOMEM;
+ goto out;
+ }
+
+ if ( mlock( pfn_type, BATCH_SIZE * sizeof(unsigned long) ) ){
+ xcio_error(ioctxt, "Unable to mlock");
+ goto out;
+ }
+
+
+ /*
+ * Quick belt and braces sanity check.
+ */
+#if DEBUG
+ for ( i = 0; i < nr_pfns; i++ ){
+ mfn = live_pfn_to_mfn_table[i];
+
+ if( (live_mfn_to_pfn_table[mfn] != i) && (mfn != 0x80000004) )
+ printf("i=0x%x mfn=%x live_mfn_to_pfn_table=%x\n",
+ i,mfn,live_mfn_to_pfn_table[mfn]);
+ }
+#endif
+
+ /* Map the shared info frame */
+ live_shinfo = mfn_mapper_map_single(xc_handle, domid,
+ PAGE_SIZE, PROT_READ,
+ shared_info_frame);
+
+ if (!live_shinfo){
+ xcio_error(ioctxt, "Couldn't map live_shinfo");
+ goto out;
+ }
+
+ /* Start writing out the saved-domain record. */
+
+ if ( xcio_write(ioctxt, "LinuxGuestRecord", 16) ||
+ xcio_write(ioctxt, name, sizeof(name)) ||
+ xcio_write(ioctxt, &nr_pfns, sizeof(unsigned long)) ||
+ xcio_write(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) ){
+ xcio_error(ioctxt, "Error writing header");
+ goto out;
+ }
+ if(write_vmconfig(ioctxt)){
+ xcio_error(ioctxt, "Error writing vmconfig");
+ goto out;
+ }
+
+ print_stats( xc_handle, domid, 0, &stats, 0 );
+
+ /* Now write out each data page, canonicalising page tables as we go... */
+
+ while(1){
+ unsigned int prev_pc, sent_this_iter, N, batch;
+
+ iter++;
+ sent_this_iter = 0;
+ skip_this_iter = 0;
+ prev_pc = 0;
+ N=0;
+
+ xcio_info(ioctxt, "Saving memory pages: iter %d 0%%", iter);
+
+ while( N < nr_pfns ){
+ unsigned int this_pc = (N * 100) / nr_pfns;
+
+ if ( (this_pc - prev_pc) >= 5 ){
+ xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc);
+ prev_pc = this_pc;
+ }
+
+ /* slightly wasteful to peek the whole array evey time,
+ but this is fast enough for the moment. */
+
+ if ( !last_iter &&
+ xc_shadow_control(xc_handle, domid,
+ DOM0_SHADOW_CONTROL_OP_PEEK,
+ to_skip, nr_pfns, NULL) != nr_pfns ) {
+ xcio_error(ioctxt, "Error peeking shadow bitmap");
+ goto out;
+ }
+
+
+ /* load pfn_type[] with the mfn of all the pages we're doing in
+ this batch. */
+
+ for ( batch = 0; batch < BATCH_SIZE && N < nr_pfns ; N++ )
+ {
+ int n = permute(N, nr_pfns, order_nr );
+
+ if ( 0 && debug ) {
+ fprintf(stderr,"%d pfn= %08lx mfn= %08lx %d "
+ " [mfn]= %08lx\n",
+ iter, (unsigned long)n, live_pfn_to_mfn_table[n],
+ test_bit(n,to_send),
+ live_mfn_to_pfn_table[live_pfn_to_mfn_table[n]&
+ 0xFFFFF]);
+ }
+
+ if ( !last_iter &&
+ test_bit(n, to_send) &&
+ test_bit(n, to_skip) ) {
+ skip_this_iter++; /* stats keeping */
+ }
+
+ if ( !((test_bit(n, to_send) && !test_bit(n, to_skip)) ||
+ (test_bit(n, to_send) && last_iter) ||
+ (test_bit(n, to_fix) && last_iter)) ) {
+ continue;
+ }
+
+ /* we get here if:
+ 1. page is marked to_send & hasn't already been re-dirtied
+ 2. (ignore to_skip in last iteration)
+ 3. add in pages that still need fixup (net bufs)
+ */
+
+ pfn_batch[batch] = n;
+ pfn_type[batch] = live_pfn_to_mfn_table[n];
+
+ if( pfn_type[batch] == 0x80000004 ){
+ /* not currently in pusedo-physical map -- set bit
+ in to_fix that we must send this page in last_iter
+ unless its sent sooner anyhow */
+
+ set_bit( n, to_fix );
+ if( iter>1 )
+ DDPRINTF("netbuf race: iter %d, pfn %lx. mfn %lx\n",
+ iter,n,pfn_type[batch]);
+ continue;
+ }
+
+ if ( last_iter &&
+ test_bit(n, to_fix) &&
+ !test_bit(n, to_send) )
+ {
+ needed_to_fix++;
+ DPRINTF("Fix! iter %d, pfn %lx. mfn %lx\n",
+ iter,n,pfn_type[batch]);
+ }
+
+ clear_bit(n, to_fix);
+
+ batch++;
+ }
+
+ DDPRINTF("batch %d:%d (n=%d)\n", iter, batch, n);
+
+ if ( batch == 0 )
+ goto skip; /* vanishingly unlikely... */
+
+ if ( (region_base = mfn_mapper_map_batch(xc_handle, domid,
+ PROT_READ,
+ pfn_type,
+ batch)) == 0 ){
+ xcio_perror(ioctxt, "map batch failed");
+ goto out;
+ }
+
+ if ( get_pfn_type_batch(xc_handle, domid, batch, pfn_type) ){
+ xcio_error(ioctxt, "get_pfn_type_batch failed");
+ goto out;
+ }
+
+ for ( j = 0; j < batch; j++ ){
+ if ( (pfn_type[j] & LTAB_MASK) == XTAB ){
+ DDPRINTF("type fail: page %i mfn %08lx\n",j,pfn_type[j]);
+ continue;
+ }
+
+ if ( 0 && debug )
+ fprintf(stderr, "%d pfn= %08lx mfn= %08lx [mfn]= %08lx"
+ " sum= %08lx\n",
+ iter,
+ (pfn_type[j] & LTAB_MASK) | pfn_batch[j],
+ pfn_type[j],
+ live_mfn_to_pfn_table[pfn_type[j]&(~LTAB_MASK)],
+ csum_page(region_base + (PAGE_SIZE*j)));
+
+ /* canonicalise mfn->pfn */
+ pfn_type[j] = (pfn_type[j] & LTAB_MASK) | pfn_batch[j];
+ }
+
+ if ( xcio_write(ioctxt, &batch, sizeof(int) ) ){
+ xcio_error(ioctxt, "Error when writing to state file (2)");
+ goto out;
+ }
+
+ if ( xcio_write(ioctxt, pfn_type, sizeof(unsigned long)*j ) ){
+ xcio_error(ioctxt, "Error when writing to state file (3)");
+ goto out;
+ }
+
+ /* entering this loop, pfn_type is now in pfns (Not mfns) */
+ for( j = 0; j < batch; j++ ){
+ /* write out pages in batch */
+ if( (pfn_type[j] & LTAB_MASK) == XTAB){
+ DDPRINTF("SKIP BOGUS page %i mfn %08lx\n",j,pfn_type[j]);
+ continue;
+ }
+
+ if ( ((pfn_type[j] & LTAB_MASK) == L1TAB) ||
+ ((pfn_type[j] & LTAB_MASK) == L2TAB) ){
+ memcpy(page, region_base + (PAGE_SIZE*j), PAGE_SIZE);
+
+ for ( k = 0;
+ k < (((pfn_type[j] & LTAB_MASK) == L2TAB) ?
+ (HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT) :
+ 1024);
+ k++ ){
+ unsigned long pfn;
+
+ if ( !(page[k] & _PAGE_PRESENT) )
+ continue;
+
+ mfn = page[k] >> PAGE_SHIFT;
+ pfn = live_mfn_to_pfn_table[mfn];
+
+ if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
+ {
+ /* I don't think this should ever happen */
+ printf("FNI %d : [%08lx,%d] pte=%08lx, "
+ "mfn=%08lx, pfn=%08lx [mfn]=%08lx\n",
+ j, pfn_type[j], k,
+ page[k], mfn, live_mfn_to_pfn_table[mfn],
+ (live_mfn_to_pfn_table[mfn]<nr_pfns)?
+ live_pfn_to_mfn_table[
+ live_mfn_to_pfn_table[mfn]] :
+ 0xdeadbeef);
+
+ pfn = 0; /* be suspicious */
+ }
+
+ page[k] &= PAGE_SIZE - 1;
+ page[k] |= pfn << PAGE_SHIFT;
+
+#if 0
+ printf("L%d i=%d pfn=%d mfn=%d k=%d pte=%08lx "
+ "xpfn=%d\n",
+ pfn_type[j]>>28,
+ j,i,mfn,k,page[k],page[k]>>PAGE_SHIFT);
+#endif
+
+ } /* end of page table rewrite for loop */
+
+ if ( xcio_write(ioctxt, page, PAGE_SIZE) ){
+ xcio_error(ioctxt, "Error when writing to state file (4)");
+ goto out;
+ }
+
+ } /* end of it's a PT page */ else { /* normal page */
+
+ if ( xcio_write(ioctxt, region_base + (PAGE_SIZE*j),
+ PAGE_SIZE) ){
+ xcio_error(ioctxt, "Error when writing to state file (5)");
+ goto out;
+ }
+ }
+ } /* end of the write out for this batch */
+
+ sent_this_iter += batch;
+
+ } /* end of this while loop for this iteration */
+
+ munmap(region_base, batch*PAGE_SIZE);
+
+ skip:
+
+ total_sent += sent_this_iter;
+
+ xcio_info(ioctxt, "\r %d: sent %d, skipped %d, ",
+ iter, sent_this_iter, skip_this_iter );
+
+ if ( last_iter ) {
+ print_stats( xc_handle, domid, sent_this_iter, &stats, 1);
+
+ xcio_info(ioctxt, "Total pages sent= %d (%.2fx)\n",
+ total_sent, ((float)total_sent)/nr_pfns );
+ xcio_info(ioctxt, "(of which %d were fixups)\n", needed_to_fix );
+ }
+
+ if (last_iter && debug){
+ int minusone = -1;
+ memset( to_send, 0xff, (nr_pfns+8)/8 );
+ debug = 0;
+ printf("Entering debug resend-all mode\n");
+
+ /* send "-1" to put receiver into debug mode */
+ if ( xcio_write(ioctxt, &minusone, sizeof(int)) )
+ {
+ xcio_error(ioctxt, "Error when writing to state file (6)");
+ goto out;
+ }
+
+ continue;
+ }
+
+ if ( last_iter ) break;
+
+ if ( live )
+ {
+ if (
+ /* ( sent_this_iter > (sent_last_iter * 0.95) ) || */
+ (iter >= max_iters) ||
+ (sent_this_iter+skip_this_iter < 50) ||
+ (total_sent > nr_pfns*max_factor) )
+ {
+ DPRINTF("Start last iteration\n");
+ last_iter = 1;
+
+ xc_domain_pause( xc_handle, domid );
+ }
+
+ if ( xc_shadow_control( xc_handle, domid,
+ DOM0_SHADOW_CONTROL_OP_CLEAN2,
+ to_send, nr_pfns, &stats ) != nr_pfns )
+ {
+ xcio_error(ioctxt, "Error flushing shadow PT");
+ goto out;
+ }
+
+ sent_last_iter = sent_this_iter;
+
+ print_stats( xc_handle, domid, sent_this_iter, &stats, 1);
+
+ }
+
+
+ } /* end of while 1 */
+
+ DPRINTF("All memory is saved\n");
+
+ /* Success! */
+ rc = 0;
+
+ /* Zero terminate */
+ if ( xcio_write(ioctxt, &rc, sizeof(int)) )
+ {
+ xcio_error(ioctxt, "Error when writing to state file (6)");
+ goto out;
+ }
+
+ /* Get the final execution context */
+ if ( xc_domain_getfullinfo( xc_handle, domid, &op, &ctxt) )
+ {
+ xcio_perror(ioctxt, "Could not get full domain info");
+ goto out;
+ }
+
+ /* Canonicalise the suspend-record frame number. */
+ if ( !translate_mfn_to_pfn(&ctxt.cpu_ctxt.esi) ){
+ xcio_error(ioctxt, "State record is not in range of pseudophys map");
+ goto out;
+ }
+
+ /* Canonicalise each GDT frame number. */
+ for ( i = 0; i < ctxt.gdt_ents; i += 512 ) {
+ if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[i]) ) {
+ xcio_error(ioctxt, "GDT frame is not in range of pseudophys map");
+ goto out;
+ }
+ }
+
+ /* Canonicalise the page table base pointer. */
+ if ( !MFN_IS_IN_PSEUDOPHYS_MAP(ctxt.pt_base >> PAGE_SHIFT) ) {
+ xcio_error(ioctxt, "PT base is not in range of pseudophys map");
+ goto out;
+ }
+ ctxt.pt_base = live_mfn_to_pfn_table[ctxt.pt_base >> PAGE_SHIFT] <<
+ PAGE_SHIFT;
+
+ if ( xcio_write(ioctxt, &ctxt, sizeof(ctxt)) ||
+ xcio_write(ioctxt, live_shinfo, PAGE_SIZE) ) {
+ xcio_error(ioctxt, "Error when writing to state file (1)");
+ goto out;
+ }
+ munmap(live_shinfo, PAGE_SIZE);
+
+ out:
+ if ( pfn_type != NULL ) free(pfn_type);
+ DPRINTF("Save exit rc=%d\n",rc);
+ return !!rc;
+
+}
--- /dev/null
+/******************************************************************************
+ * xc_misc.c
+ *
+ * Miscellaneous control interface functions.
+ */
+
+#include "xc_private.h"
+
+int xc_interface_open(void)
+{
+ int fd = open("/proc/xen/privcmd", O_RDWR);
+ if ( fd == -1 )
+ PERROR("Could not obtain handle on privileged command interface");
+ return fd;
+}
+
+int xc_interface_close(int xc_handle)
+{
+ return close(xc_handle);
+}
+
+
+#define CONSOLE_RING_CLEAR 1
+
+int xc_readconsolering(int xc_handle,
+ char *str,
+ unsigned int max_chars,
+ int clear)
+{
+ int ret;
+ dom0_op_t op;
+
+ op.cmd = DOM0_READCONSOLE;
+ op.u.readconsole.str = (unsigned long)str;
+ op.u.readconsole.count = max_chars;
+ op.u.readconsole.cmd = clear ? CONSOLE_RING_CLEAR : 0;
+
+ if ( (ret = mlock(str, max_chars)) != 0 )
+ return ret;
+
+ if ( (ret = do_dom0_op(xc_handle, &op)) >= 0 )
+ str[ret] = '\0';
+
+ (void)munlock(str, max_chars);
+
+ return ret;
+}
+
+
+int xc_physinfo(int xc_handle,
+ xc_physinfo_t *put_info)
+{
+ int ret;
+ dom0_op_t op;
+ dom0_physinfo_t *got_info = &op.u.physinfo;
+
+ op.cmd = DOM0_PHYSINFO;
+ op.interface_version = DOM0_INTERFACE_VERSION;
+
+ if((ret = do_dom0_op(xc_handle, &op))) return ret;
+
+ put_info->ht_per_core = got_info->ht_per_core;
+ put_info->cores = got_info->cores;
+ put_info->total_pages = got_info->total_pages;
+ put_info->free_pages = got_info->free_pages;
+ put_info->cpu_khz = got_info->cpu_khz;
+
+ return 0;
+}
+
+
+int xc_sched_id(int xc_handle,
+ int *sched_id)
+{
+ int ret;
+ dom0_op_t op;
+
+ op.cmd = DOM0_SCHED_ID;
+ op.interface_version = DOM0_INTERFACE_VERSION;
+
+ if((ret = do_dom0_op(xc_handle, &op))) return ret;
+
+ *sched_id = op.u.sched_id.sched_id;
+
+ return 0;
+}
+
--- /dev/null
+/******************************************************************************
+ * xc_netbsd_build.c
+ */
+
+#include "xc_private.h"
+#define ELFSIZE 32 /* XXX */
+#include "xc_elf.h"
+#include <zlib.h>
+
+#ifdef DEBUG
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+static int loadelfimage(gzFile, int, unsigned long *, unsigned long,
+ unsigned long *, unsigned long *,
+ unsigned long *, unsigned long *);
+
+#define ELFROUND (ELFSIZE / 8)
+
+#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
+#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+
+static long get_tot_pages(int xc_handle, u32 domid)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_GETDOMAININFO;
+ op.u.getdomaininfo.domain = (domid_t)domid;
+ op.u.getdomaininfo.ctxt = NULL;
+ return (do_dom0_op(xc_handle, &op) < 0) ?
+ -1 : op.u.getdomaininfo.tot_pages;
+}
+
+static int get_pfn_list(int xc_handle,
+ u32 domid,
+ unsigned long *pfn_buf,
+ unsigned long max_pfns)
+{
+ dom0_op_t op;
+ int ret;
+ op.cmd = DOM0_GETMEMLIST;
+ op.u.getmemlist.domain = (domid_t)domid;
+ op.u.getmemlist.max_pfns = max_pfns;
+ op.u.getmemlist.buffer = pfn_buf;
+
+ if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
+ return -1;
+
+ ret = do_dom0_op(xc_handle, &op);
+
+ (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
+
+ return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
+}
+
+static int setup_guestos(int xc_handle,
+ u32 dom,
+ gzFile kernel_gfd,
+ unsigned long tot_pages,
+ unsigned long *virt_startinfo_addr,
+ unsigned long *virt_load_addr,
+ full_execution_context_t *ctxt,
+ const char *cmdline,
+ unsigned long shared_info_frame,
+ unsigned int control_evtchn)
+{
+ l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
+ l2_pgentry_t *vl2tab=NULL, *vl2e=NULL;
+ unsigned long *page_array = NULL;
+ int alloc_index, num_pt_pages;
+ unsigned long l2tab;
+ unsigned long l1tab;
+ unsigned long count, pt_start;
+ unsigned long symtab_addr = 0, symtab_len = 0;
+ extended_start_info_t *start_info;
+ shared_info_t *shared_info;
+ unsigned long ksize;
+ mmu_t *mmu = NULL;
+ int pm_handle, i;
+
+ if ( (pm_handle = init_pfn_mapper((domid_t)dom)) < 0 )
+ goto error_out;
+
+ if ( (page_array = malloc(tot_pages * sizeof(unsigned long))) == NULL )
+ {
+ PERROR("Could not allocate memory");
+ goto error_out;
+ }
+
+ if ( get_pfn_list(xc_handle, dom, page_array, tot_pages) != tot_pages )
+ {
+ PERROR("Could not get the page frame list");
+ goto error_out;
+ }
+
+ if (loadelfimage(kernel_gfd, pm_handle, page_array, tot_pages,
+ virt_load_addr, &ksize, &symtab_addr, &symtab_len))
+ goto error_out;
+
+ /* ksize is kernel-image size rounded up to a page boundary. */
+
+ alloc_index = tot_pages - 1;
+
+ /* Count bottom-level PTs, rounding up. */
+ num_pt_pages = (l1_table_offset(*virt_load_addr) + tot_pages + 1023)
+ / 1024;
+
+ /* We must also count the page directory. */
+ num_pt_pages++;
+
+ /* Index of first PT page. */
+ pt_start = tot_pages - num_pt_pages;
+
+ /*
+ * First allocate page for page dir. Allocation goes backwards from the end
+ * of the allocated physical address space.
+ */
+ l2tab = page_array[alloc_index] << PAGE_SHIFT;
+ alloc_index--;
+ ctxt->pt_base = l2tab;
+
+ if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL )
+ goto error_out;
+
+ /* Initialise the page tables. */
+ if ( (vl2tab = map_pfn_writeable(pm_handle, l2tab >> PAGE_SHIFT)) == NULL )
+ goto error_out;
+ memset(vl2tab, 0, PAGE_SIZE);
+ vl2e = &vl2tab[l2_table_offset(*virt_load_addr)];
+ for ( count = 0; count < tot_pages; count++ )
+ {
+ if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
+ {
+ l1tab = page_array[alloc_index--] << PAGE_SHIFT;
+ if ( vl1tab != NULL )
+ unmap_pfn(pm_handle, vl1tab);
+ if ( (vl1tab = map_pfn_writeable(pm_handle,
+ l1tab >> PAGE_SHIFT)) == NULL )
+ goto error_out;
+ memset(vl1tab, 0, PAGE_SIZE);
+ vl1e = &vl1tab[l1_table_offset(*virt_load_addr +
+ (count<<PAGE_SHIFT))];
+ *vl2e++ = l1tab | L2_PROT;
+ }
+
+ *vl1e = (page_array[count] << PAGE_SHIFT) | L1_PROT;
+ if ( count >= pt_start )
+ *vl1e &= ~_PAGE_RW;
+ vl1e++;
+
+ if ( add_mmu_update(xc_handle, mmu,
+ (page_array[count] << PAGE_SHIFT) |
+ MMU_MACHPHYS_UPDATE, count) )
+ goto error_out;
+ }
+ unmap_pfn(pm_handle, vl1tab);
+ unmap_pfn(pm_handle, vl2tab);
+
+ /*
+ * Pin down l2tab addr as page dir page - causes hypervisor to provide
+ * correct protection for the page
+ */
+ if ( add_mmu_update(xc_handle, mmu,
+ l2tab | MMU_EXTENDED_COMMAND, MMUEXT_PIN_L2_TABLE) )
+ goto error_out;
+
+ *virt_startinfo_addr =
+ *virt_load_addr + ((alloc_index-1) << PAGE_SHIFT);
+
+ start_info = map_pfn_writeable(pm_handle, page_array[alloc_index-1]);
+ memset(start_info, 0, sizeof(*start_info));
+ start_info->pt_base = *virt_load_addr + ((tot_pages-1) << PAGE_SHIFT);
+ start_info->mod_start = symtab_addr;
+ start_info->mod_len = symtab_len;
+ start_info->nr_pages = tot_pages;
+ start_info->shared_info = shared_info_frame << PAGE_SHIFT;
+ start_info->flags = 0;
+ start_info->domain_controller_evtchn = control_evtchn;
+ strncpy(start_info->cmd_line, cmdline, MAX_CMDLINE);
+ start_info->cmd_line[MAX_CMDLINE-1] = '\0';
+ unmap_pfn(pm_handle, start_info);
+
+ /* shared_info page starts its life empty. */
+ shared_info = map_pfn_writeable(pm_handle, shared_info_frame);
+ memset(shared_info, 0, PAGE_SIZE);
+ /* Mask all upcalls... */
+ for ( i = 0; i < MAX_VIRT_CPUS; i++ )
+ shared_info->vcpu_data[i].evtchn_upcall_mask = 1;
+ unmap_pfn(pm_handle, shared_info);
+
+ /* Send the page update requests down to the hypervisor. */
+ if ( finish_mmu_updates(xc_handle, mmu) )
+ goto error_out;
+
+ free(mmu);
+ (void)close_pfn_mapper(pm_handle);
+ free(page_array);
+ return 0;
+
+ error_out:
+ if ( mmu != NULL )
+ free(mmu);
+ if ( pm_handle >= 0 )
+ (void)close_pfn_mapper(pm_handle);
+ if ( page_array == NULL )
+ free(page_array);
+ return -1;
+}
+
+int xc_netbsd_build(int xc_handle,
+ u32 domid,
+ const char *image_name,
+ const char *cmdline,
+ unsigned int control_evtchn)
+{
+ dom0_op_t launch_op, op;
+ unsigned long load_addr;
+ long tot_pages;
+ int kernel_fd = -1;
+ gzFile kernel_gfd = NULL;
+ int rc, i;
+ full_execution_context_t st_ctxt, *ctxt = &st_ctxt;
+ unsigned long virt_startinfo_addr;
+
+ if ( (tot_pages = get_tot_pages(xc_handle, domid)) < 0 )
+ {
+ PERROR("Could not find total pages for domain");
+ return 1;
+ }
+
+ kernel_fd = open(image_name, O_RDONLY);
+ if ( kernel_fd < 0 )
+ {
+ PERROR("Could not open kernel image");
+ return 1;
+ }
+
+ if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
+ {
+ PERROR("Could not allocate decompression state for state file");
+ close(kernel_fd);
+ return 1;
+ }
+
+ if ( mlock(&st_ctxt, sizeof(st_ctxt) ) )
+ {
+ PERROR("Unable to mlock ctxt");
+ return 1;
+ }
+
+ op.cmd = DOM0_GETDOMAININFO;
+ op.u.getdomaininfo.domain = (domid_t)domid;
+ op.u.getdomaininfo.ctxt = ctxt;
+ if ( (do_dom0_op(xc_handle, &op) < 0) ||
+ ((u32)op.u.getdomaininfo.domain != domid) )
+ {
+ PERROR("Could not get info on domain");
+ goto error_out;
+ }
+ if ( !(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED) ||
+ (op.u.getdomaininfo.ctxt->pt_base != 0) )
+ {
+ ERROR("Domain is already constructed");
+ goto error_out;
+ }
+
+ if ( setup_guestos(xc_handle, domid, kernel_gfd, tot_pages,
+ &virt_startinfo_addr,
+ &load_addr, &st_ctxt, cmdline,
+ op.u.getdomaininfo.shared_info_frame,
+ control_evtchn) < 0 )
+ {
+ ERROR("Error constructing guest OS");
+ goto error_out;
+ }
+
+ if ( kernel_fd >= 0 )
+ close(kernel_fd);
+ if( kernel_gfd )
+ gzclose(kernel_gfd);
+
+ ctxt->flags = 0;
+
+ /*
+ * Initial register values:
+ * DS,ES,FS,GS = FLAT_GUESTOS_DS
+ * CS:EIP = FLAT_GUESTOS_CS:start_pc
+ * SS:ESP = FLAT_GUESTOS_DS:start_stack
+ * ESI = start_info
+ * [EAX,EBX,ECX,EDX,EDI,EBP are zero]
+ * EFLAGS = IF | 2 (bit 1 is reserved and should always be 1)
+ */
+ ctxt->cpu_ctxt.ds = FLAT_GUESTOS_DS;
+ ctxt->cpu_ctxt.es = FLAT_GUESTOS_DS;
+ ctxt->cpu_ctxt.fs = FLAT_GUESTOS_DS;
+ ctxt->cpu_ctxt.gs = FLAT_GUESTOS_DS;
+ ctxt->cpu_ctxt.ss = FLAT_GUESTOS_DS;
+ ctxt->cpu_ctxt.cs = FLAT_GUESTOS_CS;
+ ctxt->cpu_ctxt.eip = load_addr;
+ ctxt->cpu_ctxt.esp = virt_startinfo_addr;
+ ctxt->cpu_ctxt.esi = virt_startinfo_addr;
+ ctxt->cpu_ctxt.eflags = (1<<9) | (1<<2);
+
+ /* FPU is set up to default initial state. */
+ memset(ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
+
+ /* Virtual IDT is empty at start-of-day. */
+ for ( i = 0; i < 256; i++ )
+ {
+ ctxt->trap_ctxt[i].vector = i;
+ ctxt->trap_ctxt[i].cs = FLAT_GUESTOS_CS;
+ }
+ ctxt->fast_trap_idx = 0;
+
+ /* No LDT. */
+ ctxt->ldt_ents = 0;
+
+ /* Use the default Xen-provided GDT. */
+ ctxt->gdt_ents = 0;
+
+ /* Ring 1 stack is the initial stack. */
+ ctxt->guestos_ss = FLAT_GUESTOS_DS;
+ ctxt->guestos_esp = virt_startinfo_addr;
+
+ /* No debugging. */
+ memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
+
+ /* No callback handlers. */
+ ctxt->event_callback_cs = FLAT_GUESTOS_CS;
+ ctxt->event_callback_eip = 0;
+ ctxt->failsafe_callback_cs = FLAT_GUESTOS_CS;
+ ctxt->failsafe_callback_eip = 0;
+
+ memset( &launch_op, 0, sizeof(launch_op) );
+
+ launch_op.u.builddomain.domain = (domid_t)domid;
+ launch_op.u.builddomain.ctxt = ctxt;
+ launch_op.cmd = DOM0_BUILDDOMAIN;
+ rc = do_dom0_op(xc_handle, &launch_op);
+
+ return rc;
+
+ error_out:
+ if ( kernel_fd >= 0 )
+ close(kernel_fd);
+ if( kernel_gfd )
+ gzclose(kernel_gfd);
+
+ return -1;
+}
+
+#define MYSEEK_BUFSIZE 1024
+static off_t
+myseek(gzFile gfd, off_t offset, int whence)
+{
+ unsigned char tmp[MYSEEK_BUFSIZE];
+ int c;
+
+ if ( offset < 0 )
+ {
+ ERROR("seek back not supported");
+ return -1;
+ }
+
+ while ( offset != 0 )
+ {
+ c = offset;
+ if ( c > MYSEEK_BUFSIZE )
+ c = MYSEEK_BUFSIZE;
+ if ( gzread(gfd, tmp, c) != c )
+ {
+ PERROR("Error seeking in image.");
+ return -1;
+ }
+ offset -= c;
+ }
+
+ return 0; /* XXX */
+}
+
+/*
+ * NetBSD memory layout:
+ *
+ * ---------------- *virt_load_addr = ehdr.e_entry (0xc0100000)
+ * | kernel text |
+ * | |
+ * ----------------
+ * | kernel data |
+ * | |
+ * ----------------
+ * | kernel bss |
+ * | |
+ * ---------------- *symtab_addr
+ * | symtab size | = *symtab_len
+ * ----------------
+ * | elf header | offsets to symbol sections mangled to be relative
+ * | | to headers location
+ * ----------------
+ * | sym section |
+ * | headers |
+ * ----------------
+ * | sym sections |
+ * | |
+ * ---------------- *symtab_addr + *symtab_len
+ * | padding |
+ * ---------------- ehdr.e_entry + *ksize << PAGE_SHIFT
+ */
+
+#define IS_TEXT(p) (p.p_flags & PF_X)
+#define IS_DATA(p) (p.p_flags & PF_W)
+#define IS_BSS(p) (p.p_filesz < p.p_memsz)
+
+static int
+loadelfimage(gzFile kernel_gfd, int pm_handle, unsigned long *page_array,
+ unsigned long tot_pages, unsigned long *virt_load_addr,
+ unsigned long *ksize, unsigned long *symtab_addr,
+ unsigned long *symtab_len)
+{
+ Elf_Ehdr ehdr;
+ Elf_Phdr *phdr;
+ Elf_Shdr *shdr;
+ void *vaddr;
+ char page[PAGE_SIZE], *p;
+ unsigned long iva, maxva, symva;
+ int c, curpos, h, i, ret, s;
+
+ ret = -1;
+ phdr = NULL;
+ p = NULL;
+ maxva = 0;
+
+ if ( gzread(kernel_gfd, &ehdr, sizeof(Elf_Ehdr)) != sizeof(Elf_Ehdr) )
+ {
+ PERROR("Error reading kernel image ELF header.");
+ goto out;
+ }
+ curpos = sizeof(Elf_Ehdr);
+
+ if ( !IS_ELF(ehdr) )
+ {
+ PERROR("Image does not have an ELF header.");
+ goto out;
+ }
+
+ *virt_load_addr = ehdr.e_entry;
+
+ if ( (*virt_load_addr & (PAGE_SIZE-1)) != 0 )
+ {
+ ERROR("We can only deal with page-aligned load addresses");
+ goto out;
+ }
+
+ if ( (*virt_load_addr + (tot_pages << PAGE_SHIFT)) >
+ HYPERVISOR_VIRT_START )
+ {
+ ERROR("Cannot map all domain memory without hitting Xen space");
+ goto out;
+ }
+
+
+ phdr = malloc(ehdr.e_phnum * sizeof(Elf_Phdr));
+ if ( phdr == NULL )
+ {
+ ERROR("Cannot allocate memory for Elf_Phdrs");
+ goto out;
+ }
+
+ if ( myseek(kernel_gfd, ehdr.e_phoff - curpos, SEEK_SET) == -1 )
+ {
+ ERROR("Seek to program header failed");
+ goto out;
+ }
+ curpos = ehdr.e_phoff;
+
+ if ( gzread(kernel_gfd, phdr, ehdr.e_phnum * sizeof(Elf_Phdr)) !=
+ ehdr.e_phnum * sizeof(Elf_Phdr) )
+ {
+ PERROR("Error reading kernel image ELF program header.");
+ goto out;
+ }
+ curpos += ehdr.e_phnum * sizeof(Elf_Phdr);
+
+ /* Copy run-time 'load' segments that are writeable and/or executable. */
+ for ( h = 0; h < ehdr.e_phnum; h++ )
+ {
+ if ( (phdr[h].p_type != PT_LOAD) ||
+ ((phdr[h].p_flags & (PF_W|PF_X)) == 0) )
+ continue;
+
+ if ( IS_TEXT(phdr[h]) || IS_DATA(phdr[h]) )
+ {
+ if ( myseek(kernel_gfd, phdr[h].p_offset - curpos,
+ SEEK_SET) == -1 )
+ {
+ ERROR("Seek to section failed");
+ goto out;
+ }
+ curpos = phdr[h].p_offset;
+
+ for ( iva = phdr[h].p_vaddr;
+ iva < phdr[h].p_vaddr + phdr[h].p_filesz;
+ iva += c)
+ {
+ c = PAGE_SIZE - (iva & (PAGE_SIZE - 1));
+ if (iva + c > phdr[h].p_vaddr + phdr[h].p_filesz)
+ c = phdr[h].p_vaddr + phdr[h].p_filesz - iva;
+ if ( gzread(kernel_gfd, page, c) != c )
+ {
+ PERROR("Error reading kernel image page.");
+ goto out;
+ }
+ curpos += c;
+ vaddr = map_pfn_writeable(pm_handle,
+ page_array[(iva - *virt_load_addr)
+ >> PAGE_SHIFT]);
+ if ( vaddr == NULL )
+ {
+ ERROR("Couldn't map guest memory");
+ goto out;
+ }
+ DPRINTF(("copy page %p to %p, count 0x%x\n", (void *)iva,
+ vaddr + (iva & (PAGE_SIZE - 1)), c));
+ memcpy(vaddr + (iva & (PAGE_SIZE - 1)), page, c);
+ unmap_pfn(pm_handle, vaddr);
+ }
+
+ if ( phdr[h].p_vaddr + phdr[h].p_filesz > maxva )
+ maxva = phdr[h].p_vaddr + phdr[h].p_filesz;
+ }
+
+ if ( IS_BSS(phdr[h]) )
+ {
+ /* XXX maybe clear phdr[h].p_memsz bytes from
+ phdr[h].p_vaddr + phdr[h].p_filesz ??? */
+ if (phdr[h].p_vaddr + phdr[h].p_memsz > maxva)
+ maxva = phdr[h].p_vaddr + phdr[h].p_memsz;
+ DPRINTF(("bss from %p to %p, maxva %p\n",
+ (void *)(phdr[h].p_vaddr + phdr[h].p_filesz),
+ (void *)(phdr[h].p_vaddr + phdr[h].p_memsz),
+ (void *)maxva));
+ }
+ }
+
+ p = malloc(sizeof(int) + sizeof(Elf_Ehdr) +
+ ehdr.e_shnum * sizeof(Elf_Shdr));
+ if ( p == NULL )
+ {
+ ERROR("Cannot allocate memory for Elf_Shdrs");
+ goto out;
+ }
+
+ shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr));
+
+ if ( myseek(kernel_gfd, ehdr.e_shoff - curpos, SEEK_SET) == -1 )
+ {
+ ERROR("Seek to symbol header failed");
+ goto out;
+ }
+ curpos = ehdr.e_shoff;
+
+ if ( gzread(kernel_gfd, shdr, ehdr.e_shnum * sizeof(Elf_Shdr)) !=
+ ehdr.e_shnum * sizeof(Elf_Shdr) )
+ {
+ PERROR("Error reading kernel image ELF symbol header.");
+ goto out;
+ }
+ curpos += ehdr.e_shnum * sizeof(Elf_Shdr);
+
+ maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
+ symva = maxva;
+ maxva += sizeof(int);
+ *symtab_addr = maxva;
+ *symtab_len = 0;
+ maxva += sizeof(Elf_Ehdr) + ehdr.e_shnum * sizeof(Elf_Shdr);
+ maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
+
+ /* Copy kernel string / symbol tables into physical memory */
+ for ( h = 0; h < ehdr.e_shnum; h++ )
+ {
+ if ( shdr[h].sh_type == SHT_STRTAB )
+ {
+ /* Look for a strtab @i linked to symtab @h. */
+ for ( i = 0; i < ehdr.e_shnum; i++ )
+ if ( (shdr[i].sh_type == SHT_SYMTAB) &&
+ (shdr[i].sh_link == h) )
+ break;
+ /* Skip symtab @h if we found no corresponding strtab @i. */
+ if ( i == ehdr.e_shnum )
+ {
+ shdr[h].sh_offset = 0;
+ continue;
+ }
+ }
+
+ if ( (shdr[h].sh_type == SHT_STRTAB) ||
+ (shdr[h].sh_type == SHT_SYMTAB) )
+ {
+ if ( myseek(kernel_gfd, shdr[h].sh_offset - curpos,
+ SEEK_SET) == -1 )
+ {
+ ERROR("Seek to symbol section failed");
+ goto out;
+ }
+ curpos = shdr[h].sh_offset;
+
+ /* Mangled to be based on ELF header location. */
+ shdr[h].sh_offset = maxva - *symtab_addr;
+
+ DPRINTF(("copy section %d, size 0x%x\n", h, shdr[h].sh_size));
+ for ( i = 0; i < shdr[h].sh_size; i += c, maxva += c )
+ {
+ c = PAGE_SIZE - (maxva & (PAGE_SIZE - 1));
+ if ( c > (shdr[h].sh_size - i) )
+ c = shdr[h].sh_size - i;
+ if ( gzread(kernel_gfd, page, c) != c )
+ {
+ PERROR("Error reading kernel image page.");
+ goto out;
+ }
+ curpos += c;
+
+ vaddr = map_pfn_writeable(pm_handle,
+ page_array[(maxva - *virt_load_addr)
+ >> PAGE_SHIFT]);
+ if ( vaddr == NULL )
+ {
+ ERROR("Couldn't map guest memory");
+ goto out;
+ }
+ DPRINTF(("copy page %p to %p, count 0x%x\n", (void *)maxva,
+ vaddr + (maxva & (PAGE_SIZE - 1)), c));
+ memcpy(vaddr + (maxva & (PAGE_SIZE - 1)), page, c);
+ unmap_pfn(pm_handle, vaddr);
+ }
+
+ *symtab_len += shdr[h].sh_size;
+ maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
+
+ }
+ shdr[h].sh_name = 0; /* Name is NULL. */
+ }
+
+ if ( *symtab_len == 0 )
+ {
+ DPRINTF(("no symbol table\n"));
+ *symtab_addr = 0;
+ ret = 0;
+ goto out;
+ }
+
+ DPRINTF(("sym header va %p from %p/%p size %x/%x\n", (void *)symva,
+ shdr, p, ehdr.e_shnum * sizeof(Elf_Shdr),
+ ehdr.e_shnum * sizeof(Elf_Shdr) + sizeof(Elf_Ehdr)));
+ ehdr.e_phoff = 0;
+ ehdr.e_shoff = sizeof(Elf_Ehdr);
+ ehdr.e_phentsize = 0;
+ ehdr.e_phnum = 0;
+ ehdr.e_shstrndx = SHN_UNDEF;
+ memcpy(p + sizeof(int), &ehdr, sizeof(Elf_Ehdr));
+ *(int *)p = maxva - *symtab_addr;
+
+ /* Copy total length, crafted ELF header and section header table */
+ s = sizeof(int) + sizeof(Elf_Ehdr) + ehdr.e_shnum * sizeof(Elf_Shdr);
+ for ( i = 0; i < s; i += c, symva += c )
+ {
+ c = PAGE_SIZE - (symva & (PAGE_SIZE - 1));
+ if ( c > s - i )
+ c = s - i;
+ vaddr = map_pfn_writeable(pm_handle,
+ page_array[(symva - *virt_load_addr)
+ >> PAGE_SHIFT]);
+ if ( vaddr == NULL )
+ {
+ ERROR("Couldn't map guest memory");
+ goto out;
+ }
+ DPRINTF(("copy page %p to %p, count 0x%x\n", (void *)symva,
+ vaddr + (symva & (PAGE_SIZE - 1)), c));
+ memcpy(vaddr + (symva & (PAGE_SIZE - 1)), p + i,
+ c);
+ unmap_pfn(pm_handle, vaddr);
+ }
+
+ *symtab_len = maxva - *symtab_addr;
+
+ ret = 0;
+
+ out:
+ if ( ret == 0 )
+ {
+ maxva = (maxva + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+ *ksize = (maxva - *virt_load_addr) >> PAGE_SHIFT;
+
+ DPRINTF(("virt_addr %p, kpages 0x%lx, symtab_addr %p, symtab_len %p\n",
+ (void *)*virt_load_addr, *ksize, (void *)*symtab_addr,
+ (void *)*symtab_len));
+ }
+
+ if ( phdr != NULL )
+ free(phdr);
+ if ( p != NULL )
+ free(p);
+ return ret;
+}
--- /dev/null
+/******************************************************************************
+ * xc_physdev.c
+ *
+ * API for manipulating physical-device access permissions.
+ *
+ * Copyright (c) 2004, Rolf Neugebauer (Intel Research Cambridge)
+ * Copyright (c) 2004, K A Fraser (University of Cambridge)
+ */
+
+#include "xc_private.h"
+
+int xc_physdev_pci_access_modify(int xc_handle,
+ u32 domid,
+ int bus,
+ int dev,
+ int func,
+ int enable)
+{
+ dom0_op_t op;
+
+ op.cmd = DOM0_PCIDEV_ACCESS;
+ op.u.pcidev_access.domain = (domid_t)domid;
+ op.u.pcidev_access.bus = bus;
+ op.u.pcidev_access.dev = dev;
+ op.u.pcidev_access.func = func;
+ op.u.pcidev_access.enable = enable;
+
+ return do_dom0_op(xc_handle, &op);
+}
--- /dev/null
+/******************************************************************************
+ * xc_private.c
+ *
+ * Helper functions for the rest of the library.
+ */
+
+#include "xc_private.h"
+
+int init_pfn_mapper(domid_t domid)
+{
+ int fd = open("/dev/mem", O_RDWR);
+ if ( fd >= 0 )
+ (void)ioctl(fd, _IO('M', 1), (unsigned long)domid);
+ return fd;
+}
+
+int close_pfn_mapper(int pm_handle)
+{
+ return close(pm_handle);
+}
+
+void *map_pfn_writeable(int pm_handle, unsigned long pfn)
+{
+ void *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE,
+ MAP_SHARED, pm_handle, pfn << PAGE_SHIFT);
+ if ( vaddr == MAP_FAILED )
+ return NULL;
+ return vaddr;
+}
+
+void *map_pfn_readonly(int pm_handle, unsigned long pfn)
+{
+ void *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ,
+ MAP_SHARED, pm_handle, pfn << PAGE_SHIFT);
+ if ( vaddr == MAP_FAILED )
+ return NULL;
+ return vaddr;
+}
+
+void unmap_pfn(int pm_handle, void *vaddr)
+{
+ (void)munmap(vaddr, PAGE_SIZE);
+}
+
+/*******************/
+
+void * mfn_mapper_map_batch(int xc_handle, domid_t dom, int prot,
+ unsigned long *arr, int num )
+{
+ privcmd_mmapbatch_t ioctlx;
+ void *addr;
+ addr = mmap( NULL, num*PAGE_SIZE, prot, MAP_SHARED, xc_handle, 0 );
+ if (addr)
+ {
+ ioctlx.num=num;
+ ioctlx.dom=dom;
+ ioctlx.addr=(unsigned long)addr;
+ ioctlx.arr=arr;
+ if ( ioctl( xc_handle, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx ) < 0 )
+ {
+ perror("XXXXXXXX");
+ munmap(addr, num*PAGE_SIZE);
+ return 0;
+ }
+ }
+ return addr;
+
+}
+
+/*******************/
+
+void * mfn_mapper_map_single(int xc_handle, domid_t dom,
+ int size, int prot,
+ unsigned long mfn )
+{
+ privcmd_mmap_t ioctlx;
+ privcmd_mmap_entry_t entry;
+ void *addr;
+ addr = mmap( NULL, size, prot, MAP_SHARED, xc_handle, 0 );
+ if (addr)
+ {
+ ioctlx.num=1;
+ ioctlx.dom=dom;
+ ioctlx.entry=&entry;
+ entry.va=(unsigned long) addr;
+ entry.mfn=mfn;
+ entry.npages=(size+PAGE_SIZE-1)>>PAGE_SHIFT;
+ if ( ioctl( xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx ) <0 )
+ {
+ munmap(addr, size);
+ return 0;
+ }
+ }
+ return addr;
+}
+
+/*******************/
+
+/* NB: arr must be mlock'ed */
+int get_pfn_type_batch(int xc_handle,
+ u32 dom, int num, unsigned long *arr)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_GETPAGEFRAMEINFO2;
+ op.u.getpageframeinfo2.domain = (domid_t)dom;
+ op.u.getpageframeinfo2.num = num;
+ op.u.getpageframeinfo2.array = arr;
+ return do_dom0_op(xc_handle, &op);
+}
+
+#define GETPFN_ERR (~0U)
+unsigned int get_pfn_type(int xc_handle,
+ unsigned long mfn,
+ u32 dom)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_GETPAGEFRAMEINFO;
+ op.u.getpageframeinfo.pfn = mfn;
+ op.u.getpageframeinfo.domain = (domid_t)dom;
+ if ( do_dom0_op(xc_handle, &op) < 0 )
+ {
+ PERROR("Unexpected failure when getting page frame info!");
+ return GETPFN_ERR;
+ }
+ return op.u.getpageframeinfo.type;
+}
+
+
+
+/*******************/
+
+#define FIRST_MMU_UPDATE 1
+
+static int flush_mmu_updates(int xc_handle, mmu_t *mmu)
+{
+ int err = 0;
+ privcmd_hypercall_t hypercall;
+
+ if ( mmu->idx == FIRST_MMU_UPDATE )
+ return 0;
+
+ /* The first two requests set the correct subject domain (PTS and GPS). */
+ mmu->updates[0].val = (unsigned long)(mmu->subject<<16) & ~0xFFFFUL;
+ mmu->updates[0].ptr = (unsigned long)(mmu->subject<< 0) & ~0xFFFFUL;
+ mmu->updates[0].ptr |= MMU_EXTENDED_COMMAND;
+ mmu->updates[0].val |= MMUEXT_SET_SUBJECTDOM | SET_PAGETABLE_SUBJECTDOM;
+
+ hypercall.op = __HYPERVISOR_mmu_update;
+ hypercall.arg[0] = (unsigned long)mmu->updates;
+ hypercall.arg[1] = (unsigned long)mmu->idx;
+ hypercall.arg[2] = 0;
+
+ if ( mlock(mmu->updates, sizeof(mmu->updates)) != 0 )
+ {
+ PERROR("Could not lock pagetable update array");
+ err = 1;
+ goto out;
+ }
+
+ if ( do_xen_hypercall(xc_handle, &hypercall) < 0 )
+ {
+ ERROR("Failure when submitting mmu updates");
+ err = 1;
+ }
+
+ mmu->idx = FIRST_MMU_UPDATE;
+
+ (void)munlock(mmu->updates, sizeof(mmu->updates));
+
+ out:
+ return err;
+}
+
+mmu_t *init_mmu_updates(int xc_handle, domid_t dom)
+{
+ mmu_t *mmu = malloc(sizeof(mmu_t));
+ if ( mmu == NULL )
+ return mmu;
+ mmu->idx = FIRST_MMU_UPDATE;
+ mmu->subject = dom;
+ return mmu;
+}
+
+int add_mmu_update(int xc_handle, mmu_t *mmu,
+ unsigned long ptr, unsigned long val)
+{
+ mmu->updates[mmu->idx].ptr = ptr;
+ mmu->updates[mmu->idx].val = val;
+
+ if ( ++mmu->idx == MAX_MMU_UPDATES )
+ return flush_mmu_updates(xc_handle, mmu);
+
+ return 0;
+}
+
+int finish_mmu_updates(int xc_handle, mmu_t *mmu)
+{
+ return flush_mmu_updates(xc_handle, mmu);
+}
+
+
+long long xc_domain_get_cpu_usage( int xc_handle, domid_t domid )
+{
+ dom0_op_t op;
+
+ op.cmd = DOM0_GETDOMAININFO;
+ op.u.getdomaininfo.domain = (domid_t)domid;
+ op.u.getdomaininfo.ctxt = NULL;
+ if ( (do_dom0_op(xc_handle, &op) < 0) ||
+ ((u32)op.u.getdomaininfo.domain != domid) )
+ {
+ PERROR("Could not get info on domain");
+ return -1;
+ }
+ return op.u.getdomaininfo.cpu_time;
+}
+
+
+/* This is shared between save and restore, and may generally be useful. */
+unsigned long csum_page (void * page)
+{
+ int i;
+ unsigned long *p = page;
+ unsigned long long sum=0;
+
+ for ( i = 0; i < (PAGE_SIZE/sizeof(unsigned long)); i++ )
+ sum += p[i];
+
+ return sum ^ (sum>>32);
+}
--- /dev/null
+
+#ifndef __XC_PRIVATE_H__
+#define __XC_PRIVATE_H__
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <string.h>
+
+#include "xc.h"
+
+/* from xen/include/hypervisor-ifs */
+#include <hypervisor-if.h>
+#include <dom0_ops.h>
+#include <event_channel.h>
+#include <sched_ctl.h>
+
+#include <asm-xen/proc_cmd.h>
+
+/* from xend/lib */
+#include <domain_controller.h>
+
+#define _PAGE_PRESENT 0x001
+#define _PAGE_RW 0x002
+#define _PAGE_USER 0x004
+#define _PAGE_PWT 0x008
+#define _PAGE_PCD 0x010
+#define _PAGE_ACCESSED 0x020
+#define _PAGE_DIRTY 0x040
+#define _PAGE_PAT 0x080
+#define _PAGE_PSE 0x080
+#define _PAGE_GLOBAL 0x100
+
+
+#define L1_PAGETABLE_SHIFT 12
+#define L2_PAGETABLE_SHIFT 22
+
+#define ENTRIES_PER_L1_PAGETABLE 1024
+#define ENTRIES_PER_L2_PAGETABLE 1024
+
+#define PAGE_SHIFT L1_PAGETABLE_SHIFT
+#define PAGE_SIZE (1UL << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE-1))
+
+typedef unsigned long l1_pgentry_t;
+typedef unsigned long l2_pgentry_t;
+
+#define l1_table_offset(_a) \
+ (((_a) >> L1_PAGETABLE_SHIFT) & (ENTRIES_PER_L1_PAGETABLE - 1))
+#define l2_table_offset(_a) \
+ ((_a) >> L2_PAGETABLE_SHIFT)
+
+#define ERROR(_m, _a...) \
+ fprintf(stderr, "ERROR: " _m "\n" , ## _a )
+
+#define PERROR(_m, _a...) \
+ fprintf(stderr, "ERROR: " _m " (%d = %s)\n" , ## _a , \
+ errno, strerror(errno))
+
+static inline int do_privcmd(int xc_handle,
+ unsigned int cmd,
+ unsigned long data)
+{
+ return ioctl(xc_handle, cmd, data);
+}
+
+static inline int do_xen_hypercall(int xc_handle,
+ privcmd_hypercall_t *hypercall)
+{
+ return do_privcmd(xc_handle,
+ IOCTL_PRIVCMD_HYPERCALL,
+ (unsigned long)hypercall);
+}
+
+static inline int do_dom0_op(int xc_handle, dom0_op_t *op)
+{
+ int ret = -1;
+ privcmd_hypercall_t hypercall;
+
+ op->interface_version = DOM0_INTERFACE_VERSION;
+
+ hypercall.op = __HYPERVISOR_dom0_op;
+ hypercall.arg[0] = (unsigned long)op;
+
+ if ( mlock(op, sizeof(*op)) != 0 )
+ {
+ PERROR("Could not lock memory for Xen hypercall");
+ goto out1;
+ }
+
+ if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
+ {
+ if ( errno == EACCES )
+ fprintf(stderr, "Dom0 operation failed -- need to"
+ " rebuild the user-space tool set?\n");
+ goto out2;
+ }
+
+ out2: (void)munlock(op, sizeof(*op));
+ out1: return ret;
+}
+
+static inline int do_multicall_op(int xc_handle,
+ void *call_list, int nr_calls)
+{
+ int ret = -1;
+ privcmd_hypercall_t hypercall;
+
+ hypercall.op = __HYPERVISOR_multicall;
+ hypercall.arg[0] = (unsigned long)call_list;
+ hypercall.arg[1] = (unsigned long)nr_calls;
+
+ if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
+ {
+ if ( errno == EACCES )
+ fprintf(stderr, "Dom0 operation failed -- need to"
+ " rebuild the user-space tool set?\n");
+ goto out1;
+ }
+
+ out1: return ret;
+}
+
+/*
+ * PFN mapping.
+ */
+int init_pfn_mapper(domid_t domid);
+int close_pfn_mapper(int pm_handle);
+void *map_pfn_writeable(int pm_handle, unsigned long pfn);
+void *map_pfn_readonly(int pm_handle, unsigned long pfn);
+void unmap_pfn(int pm_handle, void *vaddr);
+int get_pfn_type_batch(int xc_handle, u32 dom, int num, unsigned long *arr);
+unsigned long csum_page (void * page);
+
+/*
+ * MMU updates.
+ */
+#define MAX_MMU_UPDATES 1024
+typedef struct {
+ mmu_update_t updates[MAX_MMU_UPDATES];
+ int idx;
+ domid_t subject;
+} mmu_t;
+mmu_t *init_mmu_updates(int xc_handle, domid_t dom);
+int add_mmu_update(int xc_handle, mmu_t *mmu,
+ unsigned long ptr, unsigned long val);
+int finish_mmu_updates(int xc_handle, mmu_t *mmu);
+
+
+/*
+ * ioctl-based mfn mapping interface
+ */
+
+/*
+typedef struct privcmd_mmap_entry {
+ unsigned long va;
+ unsigned long mfn;
+ unsigned long npages;
+} privcmd_mmap_entry_t;
+
+typedef struct privcmd_mmap {
+ int num;
+ domid_t dom;
+ privcmd_mmap_entry_t *entry;
+} privcmd_mmap_t;
+*/
+
+#define mfn_mapper_queue_size 128
+
+typedef struct mfn_mapper {
+ int xc_handle;
+ int size;
+ int prot;
+ int error;
+ int max_queue_size;
+ void * addr;
+ privcmd_mmap_t ioctl;
+
+} mfn_mapper_t;
+
+void * mfn_mapper_map_single(int xc_handle, domid_t dom, int size, int prot,
+ unsigned long mfn );
+
+void * mfn_mapper_map_batch(int xc_handle, domid_t dom, int prot,
+ unsigned long *arr, int num );
+
+mfn_mapper_t * mfn_mapper_init(int xc_handle, domid_t dom, int size, int prot);
+
+void * mfn_mapper_base(mfn_mapper_t *t);
+
+void mfn_mapper_close(mfn_mapper_t *t);
+
+int mfn_mapper_flush_queue(mfn_mapper_t *t);
+
+void * mfn_mapper_queue_entry(mfn_mapper_t *t, int offset,
+ unsigned long mfn, int size );
+
+long long xc_domain_get_cpu_usage( int xc_handle, domid_t domid );
+
+#include "xc_io.h"
+
+int xc_domain_getfullinfo(int xc_handle,
+ u32 domid,
+ dom0_op_t *op,
+ full_execution_context_t *ctxt );
+#endif /* __XC_PRIVATE_H__ */
--- /dev/null
+/******************************************************************************
+ * xc_rrobin.c
+ *
+ * API for manipulating parameters of the Round Robin scheduler
+ *
+ * by Mark Williamson, Copyright (c) 2004 Intel Research Cambridge.
+ */
+
+#include "xc_private.h"
+
+int xc_rrobin_global_set(int xc_handle, u64 slice)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_SCHEDCTL;
+ op.u.schedctl.sched_id = SCHED_RROBIN;
+ op.u.schedctl.direction = SCHED_INFO_PUT;
+
+ op.u.schedctl.u.rrobin.slice = slice;
+ return do_dom0_op(xc_handle, &op);
+}
+
+
+int xc_rrobin_global_get(int xc_handle, u64 *slice)
+{
+ dom0_op_t op;
+ int ret;
+
+ op.cmd = DOM0_SCHEDCTL;
+ op.u.schedctl.sched_id = SCHED_RROBIN;
+ op.u.schedctl.direction = SCHED_INFO_GET;
+
+ ret = do_dom0_op(xc_handle, &op);
+
+ *slice = op.u.schedctl.u.rrobin.slice;
+
+ return ret;
+}
--- /dev/null
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Make.defs
+
+CC = gcc
+
+LIB_SRCS :=
+LIB_SRCS += allocate.c
+#LIB_SRCS += enum.c
+LIB_SRCS += file_stream.c
+LIB_SRCS += gzip_stream.c
+#LIB_SRCS += hash_table.c
+LIB_SRCS += iostream.c
+#LIB_SRCS += kernel_stream.c
+#LIB_SRCS += lexis.c
+#LIB_SRCS += lzi_stream.c
+#LIB_SRCS += lzo_stream.c
+#LIB_SRCS += marshal.c
+#LIB_SRCS += socket_stream.c
+#LIB_SRCS += string_stream.c
+#LIB_SRCS += sxpr.c
+#LIB_SRCS += sxpr_parser.c
+LIB_SRCS += sys_net.c
+LIB_SRCS += sys_string.c
+#LIB_SRCS += xdr.c
+
+LIB_OBJS := $(LIB_SRCS:.c=.o)
+
+CFLAGS += -Wall
+CFLAGS += -Werror
+CFLAGS += -g
+CFLAGS += -O3
+CFLAGS += -fno-strict-aliasing
+#CFLAGS += $(INCLUDES)
+# Get gcc to generate the dependencies for us.
+CFLAGS += -Wp,-MD,.$(@F).d
+DEPS = .*.d
+
+MAJOR = 1.3
+MINOR = 0
+LIB_NAME = libxutil
+LIB_BASE = $(LIB_NAME).so
+LIB_MAJOR= $(LIB_BASE).$(MAJOR)
+LIB_MINOR= $(LIB_MAJOR).$(MINOR)
+LIB = $(LIB_BASE) $(LIB_MAJOR) $(LIB_MINOR) $(LIB_NAME).a
+
+all: check-for-zlib $(LIB)
+
+$(LIB_BASE):
+ ln -sf $(LIB_MAJOR) $@
+
+$(LIB_MAJOR):
+ ln -sf $(LIB_MINOR) $@
+
+$(LIB_MINOR): $(LIB_OBJS)
+ $(CC) -Wl,-soname -Wl,$(LIB_MAJOR) -shared -o $@ $^
+
+$(LIB_NAME).a: $(LIB_OBJS)
+ $(AR) rc $@ $^
+
+check-for-zlib:
+ @if [ ! -e /usr/include/zlib.h ]; then \
+ echo "***********************************************************"; \
+ echo "ERROR: install zlib header files (http://www.gzip.org/zlib)"; \
+ echo "***********************************************************"; \
+ false; \
+ fi
+
+install: all
+ mkdir -p $(prefix)/usr/lib
+ mkdir -p $(prefix)/usr/include
+ install -m0755 $(LIB) $(prefix)/usr/lib
+
+#install -m0644 xc.h $(prefix)/usr/include
+
+clean:
+ $(RM) *.a *.so *.o *.rpm $(LIB)
+ $(RM) *~
+ $(RM) $(DEPS)
+
+-include $(DEPS)
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "allocate.h"
+
+/** @file
+ * Support for allocating memory.
+ * Usable from user code or kernel code (with __KERNEL__ defined).
+ * In user code will use GC if USE_GC is defined.
+ */
+
+#ifdef __KERNEL__
+/*----------------------------------------------------------------------------*/
+# include <linux/config.h>
+# include <linux/slab.h>
+# include <linux/string.h>
+# include <linux/types.h>
+
+# define DEFAULT_TYPE 0
+# define MALLOC(n, type) kmalloc(n, type)
+# define FREE(ptr) kfree(ptr)
+
+/*----------------------------------------------------------------------------*/
+#else /* ! __KERNEL__ */
+
+# include <stdlib.h>
+# include <string.h>
+
+# define DEFAULT_TYPE 0
+
+#ifdef USE_GC
+# include "gc.h"
+# define MALLOC(n, typ) GC_malloc(n)
+# define FREE(ptr) (ptr=NULL)
+//typedef void *GC_PTR;
+//GC_PTR (*GC_oom_fn)(size_t n);
+#else
+# define MALLOC(n, type) malloc(n)
+# define FREE(ptr) free(ptr)
+#endif
+
+/*----------------------------------------------------------------------------*/
+#endif
+
+/** Function to call when memory cannot be allocated. */
+AllocateFailedFn *allocate_failed_fn = NULL;
+
+/** Allocate memory and zero it.
+ * The type is only relevant when calling from kernel code,
+ * from user code it is ignored.
+ * In kernel code the values accepted by kmalloc can be used:
+ * GFP_USER, GFP_ATOMIC, GFP_KERNEL.
+ *
+ * @param size number of bytes to allocate
+ * @param type memory type to allocate (kernel only)
+ * @return pointer to the allocated memory or zero
+ * if malloc failed
+ */
+void *allocate_type(int size, int type){
+ void *p = MALLOC(size, type);
+ if(p){
+ memzero(p, size);
+ } else if(allocate_failed_fn){
+ allocate_failed_fn(size, type);
+ }
+ return p;
+}
+
+/** Allocate memory and zero it.
+ *
+ * @param size number of bytes to allocate
+ * @return pointer to the allocated memory or zero
+ * if malloc failed
+ */
+void *allocate(int size){
+ return allocate_type(size, DEFAULT_TYPE);
+}
+
+/** Free memory allocated by allocate().
+ * No-op if 'p' is null.
+ *
+ * @param p memory to free
+ */
+void deallocate(void *p){
+ if(p){
+ FREE(p);
+ }
+}
+
+/** Set bytes to zero.
+ * No-op if 'p' is null.
+ *
+ * @param p memory to zero
+ * @param size number of bytes to zero
+ */
+void memzero(void *p, int size){
+ if(p){
+ memset(p, 0, (size_t)size);
+ }
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XEN_LIB_ALLOCATE_H_
+#define _XEN_LIB_ALLOCATE_H_
+
+/** Allocate memory for a given type, and cast. */
+#define ALLOCATE(ctype) (ctype *)allocate(sizeof(ctype))
+
+/** Allocate memory for a given type, and cast. */
+#define ALLOCATE_TYPE(ctype, type) (ctype *)allocate(sizeof(ctype))
+
+extern void *allocate_type(int size, int type);
+extern void *allocate(int size);
+extern void deallocate(void *);
+extern void memzero(void *p, int size);
+
+typedef void AllocateFailedFn(int size, int type);
+extern AllocateFailedFn *allocate_failed_fn;
+
+#endif /* _XEN_LIB_ALLOCATE_H_ */
+
+
+
+
+
+
+
+
+
--- /dev/null
+/*
+ * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _XEN_LIB_DEBUG_H_
+#define _XEN_LIB_DEBUG_H_
+
+#ifndef MODULE_NAME
+#define MODULE_NAME ""
+#endif
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#ifdef DEBUG
+
+#define dprintf(fmt, args...) printk(KERN_DEBUG "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
+#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
+#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
+#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
+
+#else
+
+#define dprintf(fmt, args...) do {} while(0)
+#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME fmt, ##args)
+#define iprintf(fmt, args...) printk(KERN_INFO "[INF] " MODULE_NAME fmt, ##args)
+#define eprintf(fmt, args...) printk(KERN_ERR "[ERR] " MODULE_NAME fmt, ##args)
+
+#endif
+
+#else
+
+#include <stdio.h>
+
+#ifdef DEBUG
+
+#define dprintf(fmt, args...) fprintf(stdout, "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
+#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
+#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
+#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
+
+#else
+
+#define dprintf(fmt, args...) do {} while(0)
+#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME fmt, ##args)
+#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME fmt, ##args)
+#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME fmt, ##args)
+
+#endif
+
+#endif
+
+/** Print format for an IP address.
+ * See NIPQUAD(), HIPQUAD()
+ */
+#define IPFMT "%u.%u.%u.%u"
+
+#endif /* ! _XEN_LIB_DEBUG_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef __KERNEL__
+#include <linux/errno.h>
+#else
+#include <errno.h>
+#endif
+
+#include "sys_string.h"
+#include "enum.h"
+
+/** Map an enum name to its value using a table.
+ *
+ * @param name enum name
+ * @param defs enum definitions
+ * @return enum value or -1 if not known
+ */
+int enum_name_to_val(char *name, EnumDef *defs){
+ int val = -1;
+ for(; defs->name; defs++){
+ if(!strcmp(defs->name, name)){
+ val = defs->val;
+ break;
+ }
+ }
+ return val;
+}
+
+/** Map an enum value to its name using a table.
+ *
+ * @param val enum value
+ * @param defs enum definitions
+ * @param defs_n number of definitions
+ * @return enum name or NULL if not known
+ */
+char *enum_val_to_name(int val, EnumDef *defs){
+ char *name = NULL;
+ for(; defs->name; defs++){
+ if(val == defs->val){
+ name = defs->name;
+ break;
+ }
+ }
+ return name;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XEN_LIB_ENUM_H_
+#define _XEN_LIB_ENUM_H_
+
+/** Mapping of an enum value to a name. */
+typedef struct EnumDef {
+ int val;
+ char *name;
+} EnumDef;
+
+extern int enum_name_to_val(char *name, EnumDef *defs);
+extern char *enum_val_to_name(int val, EnumDef *defs);
+
+#endif /* _XEN_LIB_ENUM_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** @file
+ * An IOStream implementation using FILE*.
+ */
+#ifndef __KERNEL__
+#include <stdio.h>
+#include <stdlib.h>
+#include "allocate.h"
+#include "file_stream.h"
+
+static int file_read(IOStream *s, void *buf, size_t n);
+static int file_write(IOStream *s, const void *buf, size_t n);
+static int file_error(IOStream *s);
+static int file_close(IOStream *s);
+static void file_free(IOStream *s);
+static int file_flush(IOStream *s);
+
+/** Methods used by a FILE* IOStream. */
+static const IOMethods file_methods = {
+ read: file_read,
+ write: file_write,
+ error: file_error,
+ close: file_close,
+ free: file_free,
+ flush: file_flush,
+};
+
+/** IOStream for stdin. */
+static IOStream _iostdin = {
+ methods: &file_methods,
+ data: (void*)1,
+};
+
+/** IOStream for stdout. */
+static IOStream _iostdout = {
+ methods: &file_methods,
+ data: (void*)2,
+};
+
+/** IOStream for stderr. */
+static IOStream _iostderr = {
+ methods: &file_methods,
+ data: (void*)3,
+};
+
+/** IOStream for stdin. */
+IOStream *iostdin = &_iostdin;
+
+/** IOStream for stdout. */
+IOStream *iostdout = &_iostdout;
+
+/** IOStream for stderr. */
+IOStream *iostderr = &_iostderr;
+
+/** Get the underlying FILE*.
+ *
+ * @param s file stream
+ * @return the stream s wraps
+ */
+static inline FILE *get_file(IOStream *s){
+ switch((long)s->data){
+ case 1: s->data = stdin; break;
+ case 2: s->data = stdout; break;
+ case 3: s->data = stderr; break;
+ }
+ return (FILE*)s->data;
+}
+
+/** Control buffering on the underlying stream, like setvbuf().
+ *
+ * @param io file stream
+ * @param buf buffer
+ * @param mode buffering mode (see man setvbuf())
+ * @param size buffer size
+ * @return 0 on success, non-zero otherwise
+ */
+int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size){
+ return setvbuf(get_file(io), buf, mode, size);
+}
+
+/** Write to the underlying stream using fwrite();
+ *
+ * @param stream input
+ * @param buf where to put input
+ * @param n number of bytes to write
+ * @return number of bytes written
+ */
+static int file_write(IOStream *s, const void *buf, size_t n){
+ return fwrite(buf, 1, n, get_file(s));
+}
+
+/** Read from the underlying stream using fread();
+ *
+ * @param stream input
+ * @param buf where to put input
+ * @param n number of bytes to read
+ * @return number of bytes read
+ */
+static int file_read(IOStream *s, void *buf, size_t n){
+ return fread(buf, 1, n, get_file(s));
+}
+
+/** Fush the underlying stream using fflush().
+ *
+ * @param s file stream
+ * @return 0 on success, error code otherwise
+ */
+static int file_flush(IOStream *s){
+ return fflush(get_file(s));
+}
+
+/** Check if a stream has an error.
+ *
+ * @param s file stream
+ * @return 1 if has an error, 0 otherwise
+ */
+static int file_error(IOStream *s){
+ return ferror(get_file(s));
+}
+
+/** Close a file stream.
+ *
+ * @param s file stream to close
+ * @return result of the close
+ */
+static int file_close(IOStream *s){
+ return fclose(get_file(s));
+}
+
+/** Free a file stream.
+ *
+ * @param s file stream
+ */
+static void file_free(IOStream *s){
+ // Do nothing - fclose does it all?
+}
+
+/** Create an IOStream for a stream.
+ *
+ * @param f stream to wrap
+ * @return new IOStream using f for i/o
+ */
+IOStream *file_stream_new(FILE *f){
+ IOStream *io = ALLOCATE(IOStream);
+ if(io){
+ io->methods = &file_methods;
+ io->data = (void*)f;
+ }
+ return io;
+}
+
+/** IOStream version of fopen().
+ *
+ * @param file name of the file to open
+ * @param flags giving the mode to open in (as for fopen())
+ * @return new stream for the open file, or 0 if failed
+ */
+IOStream *file_stream_fopen(const char *file, const char *flags){
+ IOStream *io = 0;
+ FILE *fin = fopen(file, flags);
+ if(fin){
+ io = file_stream_new(fin);
+ if(!io){
+ fclose(fin);
+ //free(fin); // fclose frees ?
+ }
+ }
+ return io;
+}
+
+/** IOStream version of fdopen().
+ *
+ * @param fd file descriptor
+ * @param flags giving the mode to open in (as for fdopen())
+ * @return new stream for the open file, or 0 if failed
+ */
+IOStream *file_stream_fdopen(int fd, const char *flags){
+ IOStream *io = 0;
+ FILE *fin = fdopen(fd, flags);
+ if(fin){
+ io = file_stream_new(fin);
+ }
+ return io;
+}
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XEN_LIB_FILE_STREAM_H_
+#define _XEN_LIB_FILE_STREAM_H_
+
+#ifndef __KERNEL__
+#include "iostream.h"
+#include <stdio.h>
+
+extern IOStream *file_stream_new(FILE *f);
+extern IOStream *file_stream_fopen(const char *file, const char *flags);
+extern IOStream *file_stream_fdopen(int fd, const char *flags);
+extern IOStream get_stream_stdout(void);
+extern IOStream get_stream_stderr(void);
+extern IOStream get_stream_stdin(void);
+
+extern int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size);
+#endif
+#endif /* !_XEN_LIB_FILE_STREAM_H_ */
--- /dev/null
+/* $Id: gzip_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */
+/*
+ * Copyright (C) 2003 Hewlett-Packard Company.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** @file
+ * An IOStream implementation using zlib gzFile to provide
+ * compression and decompression.
+ */
+#ifndef __KERNEL__
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "zlib.h"
+
+#include "allocate.h"
+#include "gzip_stream.h"
+
+static int gzip_read(IOStream *s, void *buf, size_t n);
+static int gzip_write(IOStream *s, const void *buf, size_t n);
+static int gzip_error(IOStream *s);
+static int gzip_close(IOStream *s);
+static void gzip_free(IOStream *s);
+static int gzip_flush(IOStream *s);
+
+/** Methods used by a gzFile* IOStream. */
+static const IOMethods gzip_methods = {
+ read: gzip_read,
+ write: gzip_write,
+ error: gzip_error,
+ close: gzip_close,
+ free: gzip_free,
+ flush: gzip_flush,
+};
+
+/** Get the underlying gzFile*.
+ *
+ * @param s gzip stream
+ * @return the stream s wraps
+ */
+static inline gzFile get_gzfile(IOStream *s){
+ return (gzFile)s->data;
+}
+
+/** Write to the underlying stream.
+ *
+ * @param stream destination
+ * @param buf data
+ * @param n number of bytes to write
+ * @return number of bytes written
+ */
+static int gzip_write(IOStream *s, const void *buf, size_t n){
+ return gzwrite(get_gzfile(s), (void*)buf, n);
+}
+
+/** Read from the underlying stream.
+ *
+ * @param stream input
+ * @param buf where to put input
+ * @param n number of bytes to read
+ * @return number of bytes read
+ */
+static int gzip_read(IOStream *s, void *buf, size_t n){
+ return gzread(get_gzfile(s), buf, n);
+}
+
+/** Flush the underlying stream.
+ *
+ * @param s gzip stream
+ * @return 0 on success, error code otherwise
+ */
+static int gzip_flush(IOStream *s){
+ //return gzflush(get_gzfile(s), Z_NO_FLUSH);
+ return gzflush(get_gzfile(s), Z_SYNC_FLUSH);
+ //return gzflush(get_gzfile(s), Z_FULL_FLUSH);
+}
+
+/** Check if a stream has an error.
+ *
+ * @param s gzip stream
+ * @return 1 if has an error, 0 otherwise
+ */
+static int gzip_error(IOStream *s){
+ int err;
+ gzFile *gz = get_gzfile(s);
+ gzerror(gz, &err);
+ return (err == Z_ERRNO ? 1 /* ferror(gzfile(gz)) */ : err);
+}
+
+/** Close a gzip stream.
+ *
+ * @param s gzip stream to close
+ * @return result of the close
+ */
+static int gzip_close(IOStream *s){
+ return gzclose(get_gzfile(s));
+}
+
+/** Free a gzip stream.
+ *
+ * @param s gzip stream
+ */
+static void gzip_free(IOStream *s){
+ // Do nothing - fclose does it all?
+}
+
+/** Create an IOStream for a gzip stream.
+ *
+ * @param f stream to wrap
+ * @return new IOStream using f for i/o
+ */
+IOStream *gzip_stream_new(gzFile *f){
+ IOStream *io = ALLOCATE(IOStream);
+ if(io){
+ io->methods = &gzip_methods;
+ io->data = (void*)f;
+ }
+ return io;
+}
+
+/** IOStream version of fopen().
+ *
+ * @param file name of the file to open
+ * @param flags giving the mode to open in (as for fopen())
+ * @return new stream for the open file, or NULL if failed
+ */
+IOStream *gzip_stream_fopen(const char *file, const char *flags){
+ IOStream *io = NULL;
+ gzFile *fgz;
+ fgz = gzopen(file, flags);
+ if(fgz){
+ io = gzip_stream_new(fgz);
+ if(!io){
+ gzclose(fgz);
+ //free(fgz); // gzclose frees ?
+ }
+ }
+ return io;
+}
+
+/** IOStream version of fdopen().
+ *
+ * @param fd file descriptor
+ * @param flags giving the mode to open in (as for fdopen())
+ * @return new stream for the open file, or NULL if failed
+ */
+IOStream *gzip_stream_fdopen(int fd, const char *flags){
+ IOStream *io = NULL;
+ gzFile *fgz;
+ fgz = gzdopen(fd, flags);
+ if(fgz){
+ io = gzip_stream_new(fgz);
+ }
+ return io;
+}
+#endif
--- /dev/null
+#/* $Id: gzip_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */
+/*
+ * Copyright (C) 2003 Hewlett-Packard Company.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _SP_GZIP_STREAM_H_
+#define _SP_GZIP_STREAM_H_
+
+#ifndef __KERNEL__
+#include "iostream.h"
+#include "zlib.h"
+
+extern IOStream *gzip_stream_new(gzFile *f);
+extern IOStream *gzip_stream_fopen(const char *file, const char *flags);
+extern IOStream *gzip_stream_fdopen(int fd, const char *flags);
+#endif
+#endif /* !_SP_FILE_STREAM_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef __KERNEL__
+# include <linux/config.h>
+# include <linux/module.h>
+# include <linux/kernel.h>
+# include <linux/errno.h>
+#else
+# include <errno.h>
+# include <stddef.h>
+#endif
+
+//#include <limits.h>
+
+#include "allocate.h"
+#include "hash_table.h"
+
+/** @file
+ * Base support for hashtables.
+ *
+ * Hash codes are reduced modulo the number of buckets to index tables,
+ * so there is no need for hash functions to limit the range of hashcodes.
+ * In fact it is assumed that hashcodes do not change when the number of
+ * buckets in the table changes.
+ */
+
+/*==========================================================================*/
+/** Number of bits in half a word. */
+//#if __WORDSIZE == 64
+//#define HALF_WORD_BITS 32
+//#else
+#define HALF_WORD_BITS 16
+//#endif
+
+/** Mask for lo half of a word. On 32-bit this is
+ * (1<<16) - 1 = 65535 = 0xffff
+ * It's 4294967295 = 0xffffffff on 64-bit.
+ */
+#define LO_HALF_MASK ((1 << HALF_WORD_BITS) - 1)
+
+/** Get the lo half of a word. */
+#define LO_HALF(x) ((x) & LO_HALF_MASK)
+
+/** Get the hi half of a word. */
+#define HI_HALF(x) ((x) >> HALF_WORD_BITS)
+
+/** Do a full hash on both inputs, using DES-style non-linear scrambling.
+ * Both inputs are replaced with the results of the hash.
+ *
+ * @param pleft input/output word
+ * @param pright input/output word
+ */
+void pseudo_des(unsigned long *pleft, unsigned long *pright){
+ // Bit-rich mixing constant.
+ static const unsigned long a_mixer[] = {
+ 0xbaa96887L, 0x1e17d32cL, 0x03bcdc3cL, 0x0f33d1b2L, };
+
+ // Bit-rich mixing constant.
+ static const unsigned long b_mixer[] = {
+ 0x4b0f3b58L, 0xe874f0c3L, 0x6955c5a6L, 0x55a7ca46L, };
+
+ // Number of iterations - must be 2 or 4.
+ static const int ncycle = 4;
+ //static const int ncycle = 2;
+
+ unsigned long left = *pleft, right = *pright;
+ unsigned long v, v_hi, v_lo;
+ int i;
+
+ for(i=0; i<ncycle; i++){
+ // Flip some bits in right to get v.
+ v = right;
+ v ^= a_mixer[i];
+ // Get lo and hi halves of v.
+ v_lo = LO_HALF(v);
+ v_hi = HI_HALF(v);
+ // Non-linear mix of the halves of v.
+ v = ((v_lo * v_lo) + ~(v_hi * v_hi));
+ // Swap the halves of v.
+ v = (HI_HALF(v) | (LO_HALF(v) << HALF_WORD_BITS));
+ // Flip some bits.
+ v ^= b_mixer[i];
+ // More non-linear mixing.
+ v += (v_lo * v_hi);
+ v ^= left;
+ left = right;
+ right = v;
+ }
+ *pleft = left;
+ *pright = right;
+}
+
+/** Hash a string.
+ *
+ * @param s input to hash
+ * @return hashcode
+ */
+Hashcode hash_string(char *s){
+ Hashcode h = 0;
+ if(s){
+ for( ; *s; s++){
+ h = hash_2ul(h, *s);
+ }
+ }
+ return h;
+}
+
+/** Get the bucket for a hashcode in a hash table.
+ *
+ * @param table to get bucket from
+ * @param hashcode to get bucket for
+ * @return bucket
+ */
+inline HTBucket * get_bucket(HashTable *table, Hashcode hashcode){
+ return table->buckets + (hashcode % table->buckets_n);
+}
+
+/** Initialize a hash table.
+ * Can be safely called more than once.
+ *
+ * @param table to initialize
+ */
+void HashTable_init(HashTable *table){
+ int i;
+
+ if(!table->init_done){
+ table->init_done = 1;
+ table->next_id = 0;
+ for(i=0; i<table->buckets_n; i++){
+ HTBucket *bucket = get_bucket(table, i);
+ bucket->head = 0;
+ bucket->count = 0;
+ }
+ table->entry_count = 0;
+ }
+}
+
+/** Allocate a new hashtable.
+ * If the number of buckets is not positive the default is used.
+ * The number of buckets should usually be prime.
+ *
+ * @param buckets_n number of buckets
+ * @return new hashtable or null
+ */
+HashTable *HashTable_new(int buckets_n){
+ HashTable *z = ALLOCATE(HashTable);
+ if(!z) goto exit;
+ if(buckets_n <= 0){
+ buckets_n = HT_BUCKETS_N;
+ }
+ z->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
+ if(!z->buckets){
+ deallocate(z);
+ z = 0;
+ goto exit;
+ }
+ z->buckets_n = buckets_n;
+ HashTable_init(z);
+ exit:
+ return z;
+}
+
+/** Free a hashtable.
+ * Any entries are removed and freed.
+ *
+ * @param h hashtable (ignored if null)
+ */
+void HashTable_free(HashTable *h){
+ if(h){
+ HashTable_clear(h);
+ deallocate(h->buckets);
+ deallocate(h);
+ }
+}
+
+/** Push an entry on the list in the bucket for a given hashcode.
+ *
+ * @param table to add entry to
+ * @param hashcode for the entry
+ * @param entry to add
+ */
+static inline void push_on_bucket(HashTable *table, Hashcode hashcode,
+ HTEntry *entry){
+ HTBucket *bucket;
+ HTEntry *old_head;
+
+ bucket = get_bucket(table, hashcode);
+ old_head = bucket->head;
+ bucket->count++;
+ bucket->head = entry;
+ entry->next = old_head;
+}
+
+/** Change the number of buckets in a hashtable.
+ * No-op if the number of buckets is not positive.
+ * Existing entries are reallocated to buckets based on their hashcodes.
+ * The table is unmodified if the number of buckets cannot be changed.
+ *
+ * @param table hashtable
+ * @param buckets_n new number of buckets
+ * @return 0 on success, error code otherwise
+ */
+int HashTable_set_buckets_n(HashTable *table, int buckets_n){
+ int err = 0;
+ HTBucket *old_buckets = table->buckets;
+ int old_buckets_n = table->buckets_n;
+ int i;
+
+ if(buckets_n <= 0){
+ err = -EINVAL;
+ goto exit;
+ }
+ table->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
+ if(!table->buckets){
+ err = -ENOMEM;
+ table->buckets = old_buckets;
+ goto exit;
+ }
+ table->buckets_n = buckets_n;
+ for(i=0; i<old_buckets_n; i++){
+ HTBucket *bucket = old_buckets + i;
+ HTEntry *entry, *next;
+ for(entry = bucket->head; entry; entry = next){
+ next = entry->next;
+ push_on_bucket(table, entry->hashcode, entry);
+ }
+ }
+ deallocate(old_buckets);
+ exit:
+ return err;
+}
+
+/** Adjust the number of buckets so the table is neither too full nor too empty.
+ * The table is unmodified if adjusting fails.
+ *
+ * @param table hash table
+ * @param buckets_min minimum number of buckets (use default if 0 or negative)
+ * @return 0 on success, error code otherwise
+ */
+int HashTable_adjust(HashTable *table, int buckets_min){
+ int buckets_n = 0;
+ int err = 0;
+ if(buckets_min <= 0) buckets_min = HT_BUCKETS_N;
+ if(table->entry_count >= table->buckets_n){
+ // The table is dense - expand it.
+ buckets_n = 2 * table->buckets_n;
+ } else if((table->buckets_n > buckets_min) &&
+ (4 * table->entry_count < table->buckets_n)){
+ // The table is more than minimum size and sparse - shrink it.
+ buckets_n = 2 * table->entry_count;
+ if(buckets_n < buckets_min) buckets_n = buckets_min;
+ }
+ if(buckets_n){
+ err = HashTable_set_buckets_n(table, buckets_n);
+ }
+ return err;
+}
+
+/** Allocate a new entry for a given value.
+ *
+ * @param value to put in the entry
+ * @return entry, or 0 on failure
+ */
+HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value){
+ HTEntry *z = ALLOCATE(HTEntry);
+ if(z){
+ z->hashcode = hashcode;
+ z->key = key;
+ z->value = value;
+ }
+ return z;
+}
+
+/** Free an entry.
+ *
+ * @param z entry to free
+ */
+inline void HTEntry_free(HTEntry *z){
+ if(z){
+ deallocate(z);
+ }
+}
+
+/** Free an entry in a hashtable.
+ * The table's entry_free_fn is used is defined, otherwise
+ * the HTEntry itself is freed.
+ *
+ * @param table hashtable
+ * @param entry to free
+ */
+inline void HashTable_free_entry(HashTable *table, HTEntry *entry){
+ if(!entry)return;
+ if(table && table->entry_free_fn){
+ table->entry_free_fn(table, entry);
+ } else {
+ HTEntry_free(entry);
+ }
+}
+
+/** Get the first entry satisfying a test from the bucket for the
+ * given hashcode.
+ *
+ * @param table to look in
+ * @param hashcode indicates the bucket
+ * @param test_fn test to apply to elements
+ * @param arg first argument to calls to test_fn
+ * @return entry found, or 0
+ */
+inline HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
+ TableTestFn *test_fn, TableArg arg){
+ HTBucket *bucket;
+ HTEntry *entry = 0;
+ HTEntry *next;
+
+ bucket = get_bucket(table, hashcode);
+ for(entry = bucket->head; entry; entry = next){
+ next = entry->next;
+ if(test_fn(arg, table, entry)){
+ break;
+ }
+ }
+ return entry;
+}
+
+/** Test hashtable keys for equality.
+ * Uses the table's key_equal_fn if defined, otherwise pointer equality.
+ *
+ * @param key1 key to compare
+ * @param key2 key to compare
+ * @return 1 if equal, 0 otherwise
+ */
+inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){
+ return (table->key_equal_fn ? table->key_equal_fn(key1, key2) : key1==key2);
+}
+
+/** Compute the hashcode of a hashtable key.
+ * The table's key_hash_fn is used if defined, otherwise the address of
+ * the key is hashed.
+ *
+ * @param table hashtable
+ * @param key to hash
+ * @return hashcode
+ */
+inline Hashcode HashTable_key_hash(HashTable *table, void *key){
+ return (table->key_hash_fn ? table->key_hash_fn(key) : hash_ul((unsigned long)key));
+}
+
+/** Test if an entry has a given key.
+ *
+ * @param arg containing key to test for
+ * @param table the entry is in
+ * @param entry to test
+ * @return 1 if the entry has the key, 0 otherwise
+ */
+static inline int has_key(TableArg arg, HashTable *table, HTEntry *entry){
+ return HashTable_key_equal(table, arg.ptr, entry->key);
+}
+
+/** Get an entry with a given key.
+ *
+ * @param table to search
+ * @param key to look for
+ * @return entry if found, null otherwise
+ */
+#if 0
+inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
+ TableArg arg = { ptr: key };
+ return HashTable_find_entry(table, HashTable_key_hash(table, key), has_key, arg);
+}
+#else
+inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
+ Hashcode hashcode;
+ HTBucket *bucket;
+ HTEntry *entry = 0;
+ HTEntry *next;
+
+ hashcode = HashTable_key_hash(table, key);
+ bucket = get_bucket(table, hashcode);
+ for(entry = bucket->head; entry; entry = next){
+ next = entry->next;
+ if(HashTable_key_equal(table, key, entry->key)){
+ break;
+ }
+ }
+ return entry;
+}
+#endif
+
+/** Get the value of an entry with a given key.
+ *
+ * @param table to search
+ * @param key to look for
+ * @return value if an entry was found, null otherwise
+ */
+inline void * HashTable_get(HashTable *table, void *key){
+ HTEntry *entry = HashTable_get_entry(table, key);
+ return (entry ? entry->value : 0);
+}
+
+/** Print the buckets in a table.
+ *
+ * @param table to print
+ */
+void show_buckets(HashTable *table, IOStream *io){
+ int i,j ;
+ IOStream_print(io, "entry_count=%d buckets_n=%d\n", table->entry_count, table->buckets_n);
+ for(i=0; i<table->buckets_n; i++){
+ if(0 || table->buckets[i].count>0){
+ IOStream_print(io, "bucket %3d %3d %10p ", i,
+ table->buckets[i].count,
+ table->buckets[i].head);
+ for(j = table->buckets[i].count; j>0; j--){
+ IOStream_print(io, "+");
+ }
+ IOStream_print(io, "\n");
+ }
+ }
+ HashTable_print(table, io);
+}
+
+/** Print an entry in a table.
+ *
+ * @param entry to print
+ * @param arg a pointer to an IOStream to print to
+ * @return 0
+ */
+static int print_entry(TableArg arg, HashTable *table, HTEntry *entry){
+ IOStream *io = (IOStream*)arg.ptr;
+ IOStream_print(io, " b=%4lx h=%08lx i=%08lx |-> e=%8p k=%8p v=%8p\n",
+ entry->hashcode % table->buckets_n,
+ entry->hashcode,
+ entry->index,
+ entry, entry->key, entry->value);
+ return 0;
+}
+
+/** Print a hash table.
+ *
+ * @param table to print
+ */
+void HashTable_print(HashTable *table, IOStream *io){
+ IOStream_print(io, "{\n");
+ HashTable_map(table, print_entry, (TableArg){ ptr: io });
+ IOStream_print(io, "}\n");
+}
+/*==========================================================================*/
+
+/** Get the next entry id to use for a table.
+ *
+ * @param table hash table
+ * @return non-zero entry id
+ */
+static inline unsigned long get_next_id(HashTable *table){
+ unsigned long id;
+
+ if(table->next_id == 0){
+ table->next_id = 1;
+ }
+ id = table->next_id++;
+ return id;
+}
+
+/** Add an entry to the bucket for the
+ * given hashcode.
+ *
+ * @param table to insert in
+ * @param hashcode indicates the bucket
+ * @param key to add an entry for
+ * @param value to add an entry for
+ * @return entry on success, 0 on failure
+ */
+inline HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value){
+ HTEntry *entry = HTEntry_new(hashcode, key, value);
+ if(entry){
+ entry->index = get_next_id(table);
+ push_on_bucket(table, hashcode, entry);
+ table->entry_count++;
+ }
+ return entry;
+}
+
+/** Move the front entry for a bucket to the correct point in the bucket order as
+ * defined by the order function. If this is called every time a new entry is added
+ * the bucket will be maintained in sorted order.
+ *
+ * @param table to modify
+ * @param hashcode indicates the bucket
+ * @param order entry comparison function
+ * @return 0 if an entry was moved, 1 if not
+ */
+int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order){
+ HTEntry *new_entry = NULL, *prev = NULL, *entry = NULL;
+ HTBucket *bucket;
+ int err = 1;
+
+ bucket = get_bucket(table, hashcode);
+ new_entry = bucket->head;
+ if(!new_entry || !new_entry->next) goto exit;
+ for(entry = new_entry->next; entry; prev = entry, entry = entry->next){
+ if(order(new_entry, entry) <= 0) break;
+ }
+ if(prev){
+ err = 0;
+ bucket->head = new_entry->next;
+ new_entry->next = entry;
+ prev->next = new_entry;
+ }
+ exit:
+ return err;
+}
+
+/** Add an entry to a hashtable.
+ * The entry is added to the bucket for its key's hashcode.
+ *
+ * @param table to insert in
+ * @param key to add an entry for
+ * @param value to add an entry for
+ * @return entry on success, 0 on failure
+ */
+inline HTEntry * HashTable_add(HashTable *table, void *key, void *value){
+ return HashTable_add_entry(table, HashTable_key_hash(table, key), key, value);
+}
+
+
+/** Remove entries satisfying a test from the bucket for the
+ * given hashcode.
+ *
+ * @param table to remove from
+ * @param hashcode indicates the bucket
+ * @param test_fn test to apply to elements
+ * @param arg first argument to calls to test_fn
+ * @return number of entries removed
+ */
+inline int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
+ TableTestFn *test_fn, TableArg arg){
+ HTBucket *bucket;
+ HTEntry *entry, *prev = 0, *next;
+ int removed_count = 0;
+
+ bucket = get_bucket(table, hashcode);
+ for(entry = bucket->head; entry; entry = next){
+ next = entry->next;
+ if(test_fn(arg, table, entry)){
+ if(prev){
+ prev->next = next;
+ } else {
+ bucket->head = next;
+ }
+ bucket->count--;
+ table->entry_count--;
+ removed_count++;
+ HashTable_free_entry(table, entry);
+ entry = 0;
+ }
+ prev = entry;
+ }
+ return removed_count;
+}
+
+/** Remove entries with a given key.
+ *
+ * @param table to remove from
+ * @param key of entries to remove
+ * @return number of entries removed
+ */
+inline int HashTable_remove(HashTable *table, void *key){
+#if 1
+ Hashcode hashcode;
+ HTBucket *bucket;
+ HTEntry *entry, *prev = 0, *next;
+ int removed_count = 0;
+
+ hashcode = HashTable_key_hash(table, key);
+ bucket = get_bucket(table, hashcode);
+ for(entry = bucket->head; entry; entry = next){
+ next = entry->next;
+ if(HashTable_key_equal(table, key, entry->key)){
+ if(prev){
+ prev->next = next;
+ } else {
+ bucket->head = next;
+ }
+ bucket->count--;
+ table->entry_count--;
+ removed_count++;
+ HashTable_free_entry(table, entry);
+ entry = 0;
+ }
+ prev = entry;
+ }
+ return removed_count;
+#else
+ return HashTable_remove_entry(table, HashTable_key_hash(table, key),
+ has_key, (TableArg){ ptr: key});
+#endif
+}
+
+/** Remove (and free) all the entries in a bucket.
+ *
+ * @param bucket to clear
+ */
+static inline void bucket_clear(HashTable *table, HTBucket *bucket){
+ HTEntry *entry, *next;
+
+ for(entry = bucket->head; entry; entry = next){
+ next = entry->next;
+ HashTable_free_entry(table, entry);
+ }
+ bucket->head = 0;
+ table->entry_count -= bucket->count;
+ bucket->count = 0;
+}
+
+/** Remove (and free) all the entries in a table.
+ *
+ * @param table to clear
+ */
+void HashTable_clear(HashTable *table){
+ int i, n = table->buckets_n;
+
+ for(i=0; i<n; i++){
+ bucket_clear(table, table->buckets + i);
+ }
+}
--- /dev/null
+/* $Id: hash_table.h,v 1.1 2004/03/30 16:21:26 mjw Exp $ */
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XEN_LIB_HASH_TABLE_H_
+#define _XEN_LIB_HASH_TABLE_H_
+
+#include "iostream.h"
+
+typedef unsigned long Hashcode;
+
+/** Type used to pass parameters to table functions. */
+typedef union TableArg {
+ unsigned long ul;
+ void *ptr;
+} TableArg;
+
+/** An entry in a bucket list. */
+typedef struct HTEntry {
+ /** Hashcode of the entry's key. */
+ Hashcode hashcode;
+ /** Identifier for this entry in the table. */
+ int index;
+ /** The key for this entry. */
+ void *key;
+ /** The value in this entry. */
+ void *value;
+ /** The next entry in the list. */
+ struct HTEntry *next;
+} HTEntry;
+
+/** A bucket in a rule table. */
+typedef struct HTBucket {
+ /** Number of entries in the bucket. */
+ int count;
+ /** First entry in the bucket (may be null). */
+ HTEntry *head;
+} HTBucket;
+
+/** Default number of buckets in a hash table.
+ * You want enough buckets so the lists in the buckets will typically be short.
+ * It's a good idea if this is prime, since that will help to spread hashcodes
+ * around the table.
+ */
+//#define HT_BUCKETS_N 1
+//#define HT_BUCKETS_N 3
+//#define HT_BUCKETS_N 7
+//#define HT_BUCKETS_N 17
+//#define HT_BUCKETS_N 97
+//#define HT_BUCKETS_N 211
+//#define HT_BUCKETS_N 401
+#define HT_BUCKETS_N 1021
+
+typedef struct HashTable HashTable;
+
+/** Type for a function used to select table entries. */
+typedef int TableTestFn(TableArg arg, HashTable *table, HTEntry *entry);
+
+/** Type for a function to map over table entries. */
+typedef int TableMapFn(TableArg arg, HashTable *table, HTEntry *entry);
+
+/** Type for a function to free table entries. */
+typedef void TableFreeFn(HashTable *table, HTEntry *entry);
+
+/** Type for a function to hash table keys. */
+typedef Hashcode TableHashFn(void *key);
+
+/** Type for a function to test table keys for equality. */
+typedef int TableEqualFn(void *key1, void *key2);
+
+/** Type for a function to order table entries. */
+typedef int TableOrderFn(HTEntry *e1, HTEntry *e2);
+
+/** General hash table.
+ * A hash table with a list in each bucket.
+ * Functions can be supplied for freeing entries, hashing keys, and comparing keys.
+ * These all default to 0, when default behaviour treating keys as integers is used.
+ */
+struct HashTable {
+ /** Flag indicating whether the table has been initialised. */
+ int init_done;
+ /** Next value for the id field in inserted rules. */
+ unsigned long next_id;
+ /** Number of buckets in the bucket array. */
+ int buckets_n;
+ /** Array of buckets, each with its own list. */
+ HTBucket *buckets;
+ /** Number of entries in the table. */
+ int entry_count;
+ /** Function to free keys and values in entries. */
+ TableFreeFn *entry_free_fn;
+ /** Function to hash keys. */
+ TableHashFn *key_hash_fn;
+ /** Function to compare keys for equality. */
+ TableEqualFn *key_equal_fn;
+ /** Place for the user of the table to hang extra data. */
+ void *user_data;
+};
+
+extern HashTable *HashTable_new(int bucket_n);
+extern void HashTable_free(HashTable *table);
+extern HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value);
+extern void HTEntry_free(HTEntry *entry);
+extern int HashTable_set_bucket_n(HashTable *table, int bucket_n);
+extern void HashTable_clear(HashTable *table);
+extern HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value);
+extern HTEntry * HashTable_get_entry(HashTable *table, void *key);
+extern HTEntry * HashTable_add(HashTable *table, void *key, void *value);
+extern void * HashTable_get(HashTable *table, void *key);
+extern int HashTable_remove(HashTable *table, void *key);
+extern HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
+ TableTestFn *test_fn, TableArg arg);
+extern int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
+ TableTestFn *test_fn, TableArg arg);
+//extern int HashTable_map(HashTable *table, TableMapFn *map_fn, TableArg arg);
+extern void HashTable_print(HashTable *table, IOStream *out);
+extern int HashTable_set_buckets_n(HashTable *table, int buckets_n);
+extern int HashTable_adjust(HashTable *table, int buckets_min);
+extern void pseudo_des(unsigned long *pleft, unsigned long *pright);
+extern Hashcode hash_string(char *s);
+
+extern int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order);
+
+/** Control whether to use hashing based on DES or simple
+ * hashing. DES hashing is `more random' but much more expensive.
+ */
+#define HASH_PSEUDO_DES 0
+
+/** Hash a long using a quick and dirty linear congruential random number generator.
+ * See `Numerical Recipes in C', Chapter 7, "An Even Quicker Generator".
+ *
+ * @param a value to hash
+ * @return hashed input
+ */
+static inline unsigned long lcrng_hash(unsigned long a){
+ return (1664525L * a + 1013904223L);
+}
+
+/** Hash an unsigned long.
+ *
+ * @param a input to hash
+ * @return hashcode
+ */
+static inline Hashcode hash_ul(unsigned long a){
+#if HASH_PSEUDO_DES
+ unsigned long left = a;
+ unsigned long right = 0L;
+ pseudo_des(&left, &right);
+ return right;
+#else
+ a = lcrng_hash(a);
+ a = lcrng_hash(a);
+ return a;
+#endif
+}
+
+/** Hash two unsigned longs together.
+ *
+ * @param a input to hash
+ * @param b input to hash
+ * @return hashcode
+ */
+static inline Hashcode hash_2ul(unsigned long a, unsigned long b){
+#if HASH_PSEUDO_DES
+ unsigned long left = a;
+ unsigned long right = b;
+ pseudo_des(&left, &right);
+ return right;
+#else
+ a = lcrng_hash(a);
+ a ^= b;
+ a = lcrng_hash(a);
+ return a;
+#endif
+}
+
+/** Hash a hashcode and an unsigned long together.
+ *
+ * @param a input hashcode
+ * @param b input to hash
+ * @return hashcode
+ */
+static inline Hashcode hash_hul(Hashcode a, unsigned long b){
+#if HASH_PSEUDO_DES
+ unsigned long left = a;
+ unsigned long right = b;
+ pseudo_des(&left, &right);
+ return right;
+#else
+ a ^= b;
+ a = lcrng_hash(a);
+ return a;
+#endif
+}
+
+/** Macro to declare variables for HashTable_for_each() to use.
+ *
+ * @param entry variable that is set to entries in the table
+ */
+#define HashTable_for_decl(entry) \
+ HashTable *_var_table; \
+ HTBucket *_var_bucket; \
+ HTBucket *_var_end; \
+ HTEntry *_var_next; \
+ HTEntry *entry
+
+/** Macro to iterate over the entries in a hashtable.
+ * Must be in a scope where HashTable_for_decl() has been used to declare
+ * variables for it to use.
+ * The variable 'entry' is iterated over entries in the table.
+ * The code produced is syntactically a loop, so it must be followed by
+ * a loop body, typically some statements in braces:
+ * HashTable_for_each(entry, table){ ...loop body... }
+ *
+ * HashTable_for_each() and HashTable_for_decl() cannot be used for nested
+ * loops as variables will clash.
+ *
+ * @note The simplest way to code a direct loop over the entries in a hashtable
+ * is to use a loop over the buckets, with a nested loop over the entries
+ * in a bucket. Using this approach in a macro means the macro contains
+ * an opening brace, and calls to it must be followed by 2 braces!
+ * To avoid this the code has been restructured so that it is a for loop.
+ * So that statements could be used in the test expression of the for loop,
+ * we have used the gcc statement expression extension ({ ... }).
+ *
+ * @param entry variable to iterate over the entries
+ * @param table to iterate over (non-null)
+ */
+#define HashTable_for_each(entry, table) \
+ _var_table = table; \
+ _var_bucket = _var_table->buckets; \
+ _var_end = _var_bucket + _var_table->buckets_n; \
+ for(entry=0, _var_next=0; \
+ ({ if(_var_next){ \
+ entry = _var_next; \
+ _var_next = entry->next; \
+ } else { \
+ while(_var_bucket < _var_end){ \
+ entry = _var_bucket->head; \
+ _var_bucket++; \
+ if(entry){ \
+ _var_next = entry->next; \
+ break; \
+ } \
+ } \
+ }; \
+ entry; }); \
+ entry = _var_next )
+
+/** Map a function over the entries in a table.
+ * Mapping stops when the function returns a non-zero value.
+ * Uses the gcc statement expression extension ({ ... }).
+ *
+ * @param table to map over
+ * @param fn function to apply to entries
+ * @param arg first argument to call the function with
+ * @return 0 if fn always returned 0, first non-zero value otherwise
+ */
+#define HashTable_map(table, fn, arg) \
+ ({ HashTable_for_decl(_var_entry); \
+ TableArg _var_arg = arg; \
+ int _var_value = 0; \
+ HashTable_for_each(_var_entry, table){ \
+ if((_var_value = fn(_var_arg, _var_table, _var_entry))) break; \
+ } \
+ _var_value; })
+
+/** Cast x to the type for a key or value in a hash table.
+ * This avoids compiler warnings when using short integers
+ * as keys or values (especially on 64-bit platforms).
+ */
+#define HKEY(x) ((void*)(unsigned long)(x))
+
+/** Cast x from the type for a key or value in a hash table.
+ * to an unsigned long. This avoids compiler warnings when using
+ * short integers as keys or values (especially on 64-bit platforms).
+ */
+#define HVAL(x) ((unsigned long)(x))
+
+#endif /* !_XEN_LIB_HASH_TABLE_H_ */
--- /dev/null
+#include "iostream.h"
+#include "sys_string.h"
+
+/** Print on a stream, like vfprintf().
+ *
+ * @param stream to print to
+ * @param format for the print (as fprintf())
+ * @param args arguments to print
+ * @return result code from the print
+ */
+int IOStream_vprint(IOStream *stream, const char *format, va_list args){
+ char buffer[1024];
+ int k = sizeof(buffer), n;
+
+ n = vsnprintf(buffer, k, (char*)format, args);
+ if(n < 0 || n > k ){
+ n = k;
+ }
+ n = IOStream_write(stream, buffer, n);
+ return n;
+}
+
+/** Print on a stream, like fprintf().
+ *
+ * @param stream to print to
+ * @param format for the print (as fprintf())
+ * @return result code from the print
+ */
+int IOStream_print(IOStream *stream, const char *format, ...){
+ va_list args;
+ int result = -1;
+
+ va_start(args, format);
+ result = IOStream_vprint(stream, format, args);
+ va_end(args);
+ return result;
+}
--- /dev/null
+#ifndef _XC_LINUX_SAVE_H_
+#define _XC_LINUX_SAVE_H_
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#ifdef __KERNEL__
+#include <linux/errno.h>
+#else
+#include <errno.h>
+#endif
+
+#include "allocate.h"
+
+/** End of input return value. */
+#define IOSTREAM_EOF -1
+
+/** An input/output abstraction.
+ */
+typedef struct IOStream IOStream;
+
+/** Record of the functions to use for operations on an
+ * IOStream implementation.
+ */
+typedef struct IOMethods {
+ /** Read function. Called with the user data, buffer to read into
+ * and number of bytes to read. Must return number of bytes read
+ * on success, less than zero on error.
+ */
+ int (*read)(IOStream *stream, void *buf, size_t n);
+
+ /** Write function. Called with user data, buffer to write and
+ * number of bytes to write. Must return number of bytes written on
+ * success, less than zero otherwise.
+ */
+ int (*write)(IOStream *stream, const void *buf, size_t n);
+
+ int (*flush)(IOStream *s);
+
+ int (*error)(IOStream *s);
+
+ int (*close)(IOStream *s);
+
+ void (*free)(IOStream *s);
+
+ void (*lock)(IOStream *s);
+ void (*unlock)(IOStream *s);
+
+} IOMethods;
+
+/** Abstract i/o object.
+ */
+struct IOStream {
+ /** Methods to use to implement operations. */
+ const IOMethods *methods;
+ /** Private state for the implementation. */
+ const void *data;
+ /** Flag indicating whether the stream is closed. */
+ int closed;
+ /** Number of bytes written. */
+ int written;
+ /** Number of bytes read. */
+ int read;
+};
+
+
+/** IOStream version of stdin. */
+extern IOStream *iostdin;
+
+/** IOStream version of stdout, */
+extern IOStream *iostdout;
+
+/** IOStream version of stderr. */
+extern IOStream *iostderr;
+
+extern int IOStream_print(IOStream *io, const char *format, ...);
+extern int IOStream_vprint(IOStream *io, const char *format, va_list args);
+
+/** Read from a stream.
+ *
+ * @param stream input
+ * @param buf where to put input
+ * @param n number of bytes to read
+ * @return if ok, number of bytes read, otherwise negative error code
+ */
+static inline int IOStream_read(IOStream *stream, void *buf, size_t n){
+ int result = 0;
+ if(stream->closed) goto exit;
+ if(!stream->methods || !stream->methods->read){
+ result = -EINVAL;
+ goto exit;
+ }
+ result = stream->methods->read(stream, buf, n);
+ if(result > 0){
+ stream->read += result;
+ }
+ exit:
+ return result;
+}
+
+/** Write to a stream.
+ *
+ * @param stream input
+ * @param buf where to put input
+ * @param n number of bytes to write
+ * @return if ok, number of bytes read, otherwise negative error code
+ */
+static inline int IOStream_write(IOStream *stream, const void *buf, size_t n){
+ int result = 0;
+ if(stream->closed) goto exit;
+ if(!stream->methods || !stream->methods->write){
+ result = -EINVAL;
+ goto exit;
+ }
+ result = stream->methods->write(stream, buf, n);
+ if(result > 0){
+ stream->written += result;
+ }
+ exit:
+ return result;
+}
+
+/** Flush the stream.
+ *
+ * @param stream stream
+ * @return 0 on success, IOSTREAM_EOF otherwise
+ */
+static inline int IOStream_flush(IOStream *stream){
+ int result = 0;
+ if(stream->closed){
+ result = IOSTREAM_EOF;
+ } else if(stream->methods->flush){
+ result = stream->methods->flush(stream);
+ if(result < 0) result = IOSTREAM_EOF;
+ }
+ return result;
+}
+
+/** Check whether the stream has an error.
+ *
+ * @param stream to check
+ * @return 1 for error, 0 otherwise
+ */
+static inline int IOStream_error(IOStream *stream){
+ int err = 0;
+ if(stream->methods && stream->methods->error){
+ err = stream->methods->error(stream);
+ }
+ return err;
+}
+
+/** Close the stream.
+ *
+ * @param stream to close
+ * @return 1 for error, 0 otherwise
+ */
+static inline int IOStream_close(IOStream *stream){
+ int err = 1;
+ if(stream->methods && stream->methods->close){
+ err = stream->methods->close(stream);
+ }
+ return err;
+}
+
+/** Test if the stream has been closed.
+ *
+ * @param stream to check
+ * @return 1 if closed, 0 otherwise
+ */
+static inline int IOStream_is_closed(IOStream *stream){
+ return stream->closed;
+}
+
+/** Free the memory used by the stream.
+ *
+ * @param stream to free
+ */
+static inline void IOStream_free(IOStream *stream){
+ if(stream->methods && stream->methods->free){
+ stream->methods->free(stream);
+ }
+ *stream = (IOStream){};
+ deallocate(stream);
+}
+
+
+/** Print a character to a stream, like fputc().
+ *
+ * @param stream to print to
+ * @param c character to print
+ * @return result code from the print
+ */
+static inline int IOStream_putc(IOStream *stream, int c){
+ int err;
+ unsigned char b = (unsigned char)c;
+ err = IOStream_write(stream, &b, 1);
+ if(err < 1){
+ err = IOSTREAM_EOF;
+ } else {
+ err = b;
+ }
+ return err;
+}
+
+/** Read from a stream, like fgetc().
+ *
+ * @param stream to read from
+ * @return IOSTREAM_EOF on error, character read otherwise
+ */
+static inline int IOStream_getc(IOStream *stream){
+ int err, rc;
+ unsigned char b;
+
+ err = IOStream_read(stream, &b, 1);
+ if(err < 1){
+ rc = IOSTREAM_EOF;
+ } else {
+ rc = b;
+ }
+ return rc;
+}
+
+/** Get number of bytes read.
+ *
+ * @param stream to get from
+ * @return number of bytes read
+ */
+static inline int IOStream_get_read(IOStream *stream){
+ return stream->read;
+}
+
+/** Get number of bytes written.
+ *
+ * @param stream to get from
+ * @return number of bytes written
+ */
+static inline int IOStream_get_written(IOStream *stream){
+ return stream->written;
+}
+
+
+#endif /* ! _XC_LINUX_SAVE_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** @file
+ * An IOStream implementation using printk() for output.
+ * Input is not implemented.
+ */
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "kernel_stream.h"
+#include "allocate.h"
+
+/** Number of characters in the output buffer.
+ * The kernel uses 1024 for printk, so that should suffice.
+ */
+#define BUF_N 1024
+
+/** State for a kernel stream. */
+typedef struct KernelData {
+ /** Stream lock. We need a lock to serialize access to the stream. */
+ spinlock_t lock;
+ /** Saved flags for locking. */
+ unsigned long flags;
+ /** Size of the output buffer. */
+ int buf_n;
+ /** Output buffer. */
+ char buf[BUF_N];
+} KernelData;
+
+static int kernel_write(IOStream *s, const char *msg, int n);
+static void kernel_free(IOStream *s);
+static void kernel_stream_lock(IOStream *s);
+static void kernel_stream_unlock(IOStream *s);
+
+/** Methods for a kernel stream. Output only. */
+static const IOMethods kernel_methods = {
+ write: kernel_write,
+ free: kernel_free,
+ lock: kernel_stream_lock,
+ unlock: kernel_stream_unlock,
+};
+
+/** Shared state for kernel streams.
+ * All implementations write using printk, so we can use
+ * shared state and avoid allocating it.
+ */
+static const KernelData kernel_data = {
+ lock: SPIN_LOCK_UNLOCKED,
+ flags: 0,
+ buf_n: BUF_N,
+};
+
+/** Stream for kernel printk. */
+static IOStream iokernel = {
+ methods: &kernel_methods,
+ data: &kernel_data,
+};
+
+/** Stream for kernel printk. */
+IOStream *iostdout = &iokernel;
+
+/** Stream for kernel printk. */
+IOStream *iostdin = &iokernel;
+
+/** Stream for kernel printk. */
+IOStream *iostderr = &iokernel;
+
+/** Get an output-only stream implementation using
+ * printk(). The stream uses static storage, and must not be freed.
+ *
+ * @return kernel stream
+ */
+IOStream get_stream_kernel(void){
+ return iokernel;
+}
+
+/** Obtain the lock on the stream state.
+ *
+ * @param kdata stream state
+ */
+static inline void KernelData_lock(KernelData *kdata){
+ spin_lock_irqsave(&kdata->lock, kdata->flags);
+}
+
+/** Release the lock on the stream state.
+ *
+ * @param kdata stream state
+ */
+static inline void KernelData_unlock(KernelData *kdata){
+ spin_unlock_irqrestore(&kdata->lock, kdata->flags);
+}
+
+/** Get the stream state.
+ *
+ * @param s kernel stream
+ * @return stream state
+ */
+static inline KernelData *get_kernel_data(IOStream *s){
+ return (KernelData*)s->data;
+}
+
+/** Obtain the lock on the stream state.
+ *
+ * @param s stream
+ */
+void kernel_stream_lock(IOStream *s){
+ KernelData_lock(get_kernel_data(s));
+}
+
+/** Release the lock on the stream state.
+ *
+ * @param s stream
+ */
+void kernel_stream_unlock(IOStream *s){
+ KernelData_unlock(get_kernel_data(s));
+}
+
+/** Write to a kernel stream.
+ *
+ * @param stream kernel stream
+ * @param format print format
+ * @param args print arguments
+ * @return result of the print
+ */
+static int kernel_write(IOStream *stream, const char *buf, int n){
+ KernelData *kdata = get_kernel_data(stream);
+ int k;
+ k = kdata->buf_n - 1;
+ if(n < k) k = n;
+ memcpy(kdata->buf, buf, k);
+ kdata->buf[k] = '\0'
+ printk(kdata->buf);
+ return k;
+}
+
+/** Free a kernel stream.
+ * Frees the internal state of the stream.
+ * Do not call this unless the stream was dynamically allocated.
+ * Do not call this on a stream returned from get_stream_kernel().
+ *
+ * @param io stream to free
+ */
+static void kernel_free(IOStream *io){
+ KernelData *kdata;
+ if(io == &iokernel) return;
+ kdata = get_kernel_data(io);
+ zero(kdata, sizeof(*kdata));
+ deallocate(kdata);
+}
+#endif /* __KERNEL__ */
+
+
+
+
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XEN_LIB_KERNEL_STREAM_H_
+#define _XEN_LIB_KERNEL_STREAM_H_
+
+#ifdef __KERNEL__
+#include "iostream.h"
+
+extern IOStream get_stream_kernel(void);
+#define get_stream_stdout get_stream_kernel
+
+#endif /* __KERNEL__ */
+#endif /* !_XEN_LIB_KERNEL_STREAM_H_ */
--- /dev/null
+/*
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** @file
+ * Lexical analysis.
+ */
+
+#include "sys_string.h"
+#include "lexis.h"
+#include <errno.h>
+
+/** Check if a value lies in a (closed) range.
+ *
+ * @param x value to test
+ * @param lo low end of the range
+ * @param hi high end of the range
+ * @return 1 if x is in the interval [lo, hi], 0 otherwise
+ */
+inline static int in_range(int x, int lo, int hi){
+ return (lo <= x) && (x <= hi);
+}
+
+/** Determine if a string is an (unsigned) decimal number.
+ *
+ * @param s pointer to characters to test
+ * @param n length of string
+ * @return 1 if s is a decimal number, 0 otherwise.
+ */
+int is_decimal_number(const char *s, int n){
+ int i;
+ if(n <= 0)return 0;
+ for(i = 0; i < n; i++){
+ if(!in_decimal_digit_class(s[i])) return 0;
+ }
+ return 1;
+}
+
+/** Determine if a string is a hex number.
+ * Hex numbers are 0, or start with 0x or 0X followed
+ * by a non-zero number of hex digits (0-9,a-f,A-F).
+ *
+ * @param s pointer to characters to test
+ * @param n length of string
+ * @return 1 if s is a hex number, 0 otherwise.
+ */
+int is_hex_number(const char *s, int n){
+ int i;
+ if(n <= 0) return 0;
+ if(n == 1){
+ return s[0]=='0';
+ }
+ if(n <= 3) return 0;
+ if(s[0] != '0' || (s[1] != 'x' && s[1] != 'X')) return 0;
+ for(i = 2; i < n; i++){
+ if(!in_hex_digit_class(s[i])) return 0;
+ }
+ return 1;
+}
+
+/** Test if a string matches a keyword.
+ * The comparison is case-insensitive.
+ * The comparison fails if either argument is null.
+ *
+ * @param s string
+ * @param k keyword
+ * @return 1 if they match, 0 otherwise
+ */
+int is_keyword(const char *s, const char *k){
+ return s && k && !strcasecmp(s, k);
+}
+
+/** Test if a string matches a character.
+ *
+ * @param s string
+ * @param c character (non-null)
+ * @return 1 if s contains exactly c, 0 otherwise
+ */
+int is_keychar(const char *s, char c){
+ return c && (s[0] == c) && !s[1];
+}
--- /dev/null
+/*
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _SP_LEXIS_H_
+#define _SP_LEXIS_H_
+
+#include "sys_string.h"
+#include "sys_ctype.h"
+
+/** @file
+ * Lexical analysis.
+ */
+
+/** Class of characters treated as space. */
+#define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 })
+
+/** Class of separator characters. */
+#define sep_class "{}()<>[]@!;"
+
+#define comment_class "#"
+
+/** Determine if a character is in a given class.
+ *
+ * @param c character to test
+ * @param s null-terminated string of characters in the class
+ * @return 1 if c is in the class, 0 otherwise.
+ */
+static inline int in_class(int c, const char *s){
+ return s && (strchr(s, c) != 0);
+}
+
+/** Determine if a character is in the space class.
+ *
+ * @param c character to test
+ * @return 1 if c is in the class, 0 otherwise.
+ */
+static inline int in_space_class(int c){
+ return in_class(c, space_class);
+}
+
+static inline int in_comment_class(int c){
+ return in_class(c, comment_class);
+}
+
+/** Determine if a character is in the separator class.
+ * Separator characters terminate tokens, and do not need space
+ * to separate them.
+ *
+ * @param c character to test
+ * @return 1 if c is in the class, 0 otherwise.
+ */
+static inline int in_sep_class(int c){
+ return in_class(c, sep_class);
+}
+
+/** Determine if a character is in the alpha class.
+ *
+ * @param c character to test
+ * @return 1 if c is in the class, 0 otherwise.
+ */
+static inline int in_alpha_class(int c){
+ return isalpha(c);
+}
+
+/** Determine if a character is in the octal digit class.
+ *
+ * @param c character to test
+ * @return 1 if c is in the class, 0 otherwise.
+ */
+static inline int in_octal_digit_class(int c){
+ return '0' <= c && c <= '7';
+}
+
+/** Determine if a character is in the decimal digit class.
+ *
+ * @param c character to test
+ * @return 1 if c is in the class, 0 otherwise.
+ */
+static inline int in_decimal_digit_class(int c){
+ return isdigit(c);
+}
+
+/** Determine if a character is in the hex digit class.
+ *
+ * @param c character to test
+ * @return 1 if c is in the class, 0 otherwise.
+ */
+static inline int in_hex_digit_class(int c){
+ return isdigit(c) || in_class(c, "abcdefABCDEF");
+}
+
+
+static inline int in_string_quote_class(int c){
+ return in_class(c, "'\"");
+}
+
+static inline int in_printable_class(int c){
+ return ('A' <= c && c <= 'Z')
+ || ('a' <= c && c <= 'z')
+ || ('0' <= c && c <= '9')
+ || in_class(c, "!$%&*+,-./:;<=>?@^_`{|}~");
+}
+
+extern int is_decimal_number(const char *s, int n);
+extern int is_hex_number(const char *s, int n);
+extern int is_keyword(const char *s, const char *k);
+extern int is_keychar(const char *s, char c);
+
+#endif /* !_SP_LEXIS_H_ */
--- /dev/null
+/* $Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */
+#define __FILE_ID_INFO "$Id: lzi_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $"
+#include <what.h>
+static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO;
+/*
+ * Copyright (C) 2003 Hewlett-Packard Company.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** @file
+ * An IOStream implementation using LZI to provide compression and decompression.
+ * This is designed to provide compression without output latency.
+ * Flushing an LZI stream flushes all pending data to the underlying stream.
+ * This is essential for stream-based (e.g. networked) applications.
+ *
+ * A compressed data stream is a sequence of blocks.
+ * Each block is the block size followed by the compressed data.
+ * The last block has size zero.
+ * Sizes are 4-byte unsigned in network order.
+ *
+ * This format allows compressed data to be read from a stream without reading
+ * past the logical end of compressed data.
+ *
+ * @author Mike Wray <mike.wray@hpl.hp.com>
+ */
+#ifndef __KERNEL__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include "zlib.h"
+
+#include "allocate.h"
+#include "lzi_stream.h"
+#include "file_stream.h"
+#include "marshal.h"
+
+#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZI>%s" fmt, __FUNCTION__, ##args)
+#define wprintf(fmt, args...) fprintf(stderr, "[WARN] LZI>%s" fmt, __FUNCTION__, ##args)
+#define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZI>%s" fmt, __FUNCTION__, ##args)
+#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZI>%s" fmt, __FUNCTION__, ##args)
+
+static int lzi_read(IOStream *s, void *buf, size_t size, size_t count);
+static int lzi_write(IOStream *s, const void *buf, size_t size, size_t count);
+static int lzi_print(IOStream *s, const char *msg, va_list args);
+static int lzi_getc(IOStream *s);
+static int lzi_error(IOStream *s);
+static int lzi_close(IOStream *s);
+static void lzi_free(IOStream *s);
+static int lzi_flush(IOStream *s);
+
+enum {
+ LZI_WRITE = 1,
+ LZI_READ = 2,
+};
+
+/** Methods used by a gzFile* IOStream. */
+static const IOMethods lzi_methods = {
+ read: lzi_read,
+ write: lzi_write,
+ print: lzi_print,
+ getc: lzi_getc,
+ error: lzi_error,
+ close: lzi_close,
+ free: lzi_free,
+ flush: lzi_flush,
+};
+
+#define BUFFER_SIZE (512 * 1024)
+
+typedef struct LZIState {
+ z_stream zstream;
+ void *inbuf;
+ uint32_t inbuf_size;
+ void *outbuf;
+ uint32_t outbuf_size;
+ /** Underlying stream for I/O. */
+ IOStream *io;
+ /** Flags. */
+ int flags;
+ /** Error indicator. */
+ int error;
+ int eof;
+ int plain_bytes;
+ int comp_bytes;
+ int zstream_initialized;
+ int flushed;
+} LZIState;
+
+static inline int LZIState_writeable(LZIState *s){
+ return (s->flags & LZI_WRITE) != 0;
+}
+
+static inline int LZIState_readable(LZIState *s){
+ return (s->flags & LZI_READ) != 0;
+}
+
+void LZIState_free(LZIState *z){
+ if(!z) return;
+ if(z->zstream_initialized){
+ if(LZIState_writeable(z)){
+ deflateEnd(&z->zstream);
+ } else if(LZIState_readable(z)){
+ inflateEnd(&z->zstream);
+ }
+ }
+ deallocate(z->inbuf);
+ deallocate(z->outbuf);
+ deallocate(z);
+}
+
+static int mode_flags(const char *mode, int *flags){
+ int err = 0;
+ int r=0, w=0;
+ if(!mode){
+ err = -EINVAL;
+ goto exit;
+ }
+ for(; *mode; mode++){
+ if(*mode == 'w') w = 1;
+ if(*mode == 'r') r = 1;
+ }
+ if(r + w != 1){
+ err = -EINVAL;
+ goto exit;
+ }
+ if(r) *flags |= LZI_READ;
+ if(w) *flags |= LZI_WRITE;
+ exit:
+ return err;
+}
+
+/** Get the stream state.
+ *
+ * @param s lzi stream
+ * @return stream state.
+ */
+static inline LZIState * lzi_state(IOStream *io){
+ return io->data;
+}
+
+IOStream *lzi_stream_io(IOStream *io){
+ LZIState *s = lzi_state(io);
+ return s->io;
+}
+
+static inline void set_error(LZIState *s, int err){
+ if(err < 0 && !s->error){
+ s->error = err;
+ }
+}
+
+static int zerror(LZIState *s, int err){
+ if(err){
+ //dprintf("> err=%d\n", err);
+ if(err < 0) set_error(s, -EIO);
+ }
+ return s->error;
+}
+
+int lzi_stream_plain_bytes(IOStream *io){
+ LZIState *s = lzi_state(io);
+ return s->plain_bytes;
+}
+
+int lzi_stream_comp_bytes(IOStream *io){
+ LZIState *s = lzi_state(io);
+ return s->comp_bytes;
+}
+
+float lzi_stream_ratio(IOStream *io){
+ LZIState *s = lzi_state(io);
+ float ratio = 0.0;
+ if(s->comp_bytes){
+ ratio = ((float) s->comp_bytes)/((float) s->plain_bytes);
+ }
+ return ratio;
+}
+
+static int alloc(void **p, int n){
+ *p = allocate(n);
+ return (p ? 0 : -ENOMEM);
+}
+
+LZIState * LZIState_new(IOStream *io, int flags){
+ int err = -ENOMEM;
+ int zlevel = Z_BEST_SPEED; // Level 1 compression - fastest.
+ int zstrategy = Z_DEFAULT_STRATEGY;
+ int zwindow = MAX_WBITS;
+ int zmemory = 8;
+ LZIState *z = ALLOCATE(LZIState);
+
+ //dprintf(">\n");
+ if(!z) goto exit;
+ z->io = io;
+ z->flags = flags;
+
+ if(LZIState_writeable(z)){
+ z->outbuf_size = BUFFER_SIZE;
+ /* windowBits is passed < 0 to suppress zlib header */
+ err = deflateInit2(&z->zstream, zlevel, Z_DEFLATED, -zwindow, zmemory, zstrategy);
+ if (err != Z_OK) goto exit;
+ z->zstream_initialized = 1;
+ err = alloc(&z->outbuf, z->outbuf_size);
+ if(err) goto exit;
+ z->zstream.next_out = z->outbuf;
+ z->zstream.avail_out = z->outbuf_size;
+ } else {
+ z->inbuf_size = BUFFER_SIZE;
+ err = alloc(&z->inbuf, z->inbuf_size);
+ if(err) goto exit;
+ ///z->zstream.next_in = z->inbuf;
+
+ /* windowBits is passed < 0 to tell that there is no zlib header.
+ * Note that in this case inflate *requires* an extra "dummy" byte
+ * after the compressed stream in order to complete decompression and
+ * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
+ * present after the compressed stream.
+ */
+ err = inflateInit2(&z->zstream, -zwindow);
+ if(err != Z_OK) goto exit;
+ z->zstream_initialized = 1;
+ }
+
+ exit:
+ if(err){
+ LZIState_free(z);
+ z = NULL;
+ }
+ //dprintf("< z=%p\n", z);
+ return z;
+}
+
+int read_block(LZIState *s){
+ int err = 0, k = 0;
+ //dprintf(">\n");
+ if(s->eof) goto exit;
+ err = unmarshal_uint32(s->io, &k);
+ if(err) goto exit;
+ if(k > s->inbuf_size){
+ err = -EINVAL;
+ goto exit;
+ }
+ if(k){
+ err = unmarshal_bytes(s->io, s->inbuf, k);
+ if(err) goto exit;
+ } else {
+ s->eof = 1;
+ }
+ s->zstream.avail_in = k;
+ s->zstream.next_in = s->inbuf;
+ s->comp_bytes += 4;
+ s->comp_bytes += k;
+ exit:
+ //dprintf("< err=%d\n", err);
+ return err;
+}
+
+int write_block(LZIState *s){
+ int err = 0;
+ int k = ((char*)s->zstream.next_out) - ((char*)s->outbuf);
+ int k2 = s->outbuf_size - s->zstream.avail_out;
+ //dprintf("> k=%d k2=%d\n", k, k2);
+ if(!k) goto exit;
+ err = marshal_uint32(s->io, k);
+ if(err) goto exit;
+ err = marshal_bytes(s->io, s->outbuf, k);
+ if(err) goto exit;
+ s->zstream.next_out = s->outbuf;
+ s->zstream.avail_out = s->outbuf_size;
+ s->comp_bytes += 4;
+ s->comp_bytes += k;
+ exit:
+ //dprintf("< err=%d\n", err);
+ return err;
+}
+
+int write_terminator(LZIState *s){
+ int err = 0;
+ char c = 0;
+ err = marshal_uint32(s->io, 1);
+ if(err) goto exit;
+ err = marshal_bytes(s->io, &c, 1);
+ if(err) goto exit;
+ err = marshal_uint32(s->io, 0);
+ if(err) goto exit;
+ s->comp_bytes += 9;
+ exit:
+ return err;
+}
+
+/** Write to the underlying stream using fwrite();
+ *
+ * @param io destination
+ * @param buf data
+ * @param size size of data elements
+ * @param count number of data elements to write
+ * @return number of data elements written
+ */
+static int lzi_write(IOStream *io, const void *buf, size_t size, size_t count){
+ int err = 0;
+ int n = size * count;
+ LZIState *s = lzi_state(io);
+
+ //dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n);
+ if(!LZIState_writeable(s)){
+ err = -EINVAL;
+ goto exit;
+ }
+ s->flushed = 0;
+ s->zstream.next_in = (void*)buf;
+ s->zstream.avail_in = n;
+ while(s->zstream.avail_in){
+ if(s->zstream.avail_out == 0){
+ err = write_block(s);
+ if(err) goto exit;
+ }
+ //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
+ //dprintf("> 1 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out);
+ err = zerror(s, deflate(&s->zstream, Z_NO_FLUSH));
+ //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
+ //dprintf("> 2 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out);
+ if(err) goto exit;
+ }
+ err = n;
+ s->plain_bytes += n;
+ if(size != 1) err /= size;
+ exit:
+ //dprintf("< err=%d\n", err);
+ return err;
+}
+
+
+/** Read from the underlying stream.
+ *
+ * @param io input
+ * @param buf where to put input
+ * @param size size of data elements
+ * @param count number of data elements to read
+ * @return number of data elements read
+ */
+static int lzi_read(IOStream *io, void *buf, size_t size, size_t count){
+ int err, zerr;
+ int n = size * count;
+ LZIState *s = lzi_state(io);
+
+ //dprintf("> size=%d count=%d n=%d\n", size, count, n);
+ if(!LZIState_readable(s)){
+ err = -EINVAL;
+ goto exit;
+ }
+ s->zstream.next_out = buf;
+ s->zstream.avail_out = n;
+ while(s->zstream.avail_out){
+ if(s->zstream.avail_in == 0){
+ err = read_block(s);
+ }
+ //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
+ zerr = inflate(&s->zstream, Z_NO_FLUSH);
+ //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
+ if(zerr == Z_STREAM_END) break;
+ //dprintf("> zerr=%d\n", zerr);
+ err = zerror(s, zerr);
+ if(err) goto exit;
+ }
+ err = n - s->zstream.avail_out;
+ s->plain_bytes += err;
+ if(size != 1) err /= size;
+ exit:
+ set_error(s, err);
+ //dprintf("< err=%d\n", err);
+ return err;
+}
+
+/** Print to the underlying stream.
+ * Returns 0 if the formatted output is too big for the internal buffer.
+ *
+ * @param io lzi stream
+ * @param msg format to use
+ * @param args arguments
+ * @return result of the print
+ */
+static int lzi_print(IOStream *io, const char *msg, va_list args){
+ char buf[1024];
+ int buf_n = sizeof(buf);
+ int n;
+ LZIState *s = lzi_state(io);
+ if(!LZIState_writeable(s)){
+ n = -EINVAL;
+ goto exit;
+ }
+ n = vsnprintf(buf, buf_n, (char*)msg, args);
+ if(n < 0) goto exit;
+ if(n > buf_n){
+ n = 0;
+ } else {
+ n = lzi_write(io, buf, 1, n);
+ }
+ exit:
+ return n;
+}
+
+/** Read a character from the underlying stream
+ *
+ * @param io lzi stream
+ * @return character read, IOSTREAM_EOF on end of file (or error)
+ */
+static int lzi_getc(IOStream *io){
+ int err;
+ char c;
+ err = lzi_read(io, &c, 1, 1);
+ if(err < 1) c = EOF;
+ err = (c==EOF ? IOSTREAM_EOF : c);
+ return err;
+}
+
+static int flush_output(LZIState *s, int mode){
+ int err = 0, zerr;
+ int done = 0;
+ int avail_out_old;
+ int count = 10;
+
+ //dprintf("> avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
+ if(s->flushed == 1 + mode) goto exit;
+ //s->zstream.avail_in = 0; /* should be zero already anyway */
+ for(;;){
+ // Write any available output.
+ if(done || s->zstream.avail_out == 0){
+ err = write_block(s);
+ if(err) goto exit;
+ if(done) break;
+ }
+ //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
+ avail_out_old = s->zstream.avail_out;
+ zerr = deflate(&s->zstream, mode);
+ err = zerror(s, zerr);
+ //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
+ //dprintf("> deflate=%d\n", err);
+ //done = (s->zstream.avail_out != 0);
+ //done = (s->zstream.avail_in == 0) && (s->zstream.avail_out == avail_out_old);
+ if(0 && mode == Z_FINISH){
+ done = (zerr == Z_STREAM_END);
+ } else {
+ done = (s->zstream.avail_in == 0)
+ //&& (s->zstream.avail_out == avail_out_old)
+ && (s->zstream.avail_out != 0);
+ }
+ }
+ s->flushed = 1 + mode;
+ exit:
+ //dprintf("< err=%d\n", err);
+ return err;
+}
+
+/** Flush any pending input to the underlying stream.
+ *
+ * @param s lzi stream
+ * @return 0 on success, error code otherwise
+ */
+static int lzi_flush(IOStream *io){
+ int err = 0;
+ LZIState *s = lzi_state(io);
+ //dprintf(">\n");
+ if(!LZIState_writeable(s)){
+ err = -EINVAL;
+ goto exit;
+ }
+ err = flush_output(s, Z_SYNC_FLUSH);
+ if(err) goto exit;
+ err = IOStream_flush(s->io);
+ exit:
+ set_error(s, err);
+ //dprintf("< err=%d\n", err);
+ return (err < 0 ? err : 0);
+}
+
+/** Check if a stream has an error.
+ *
+ * @param s lzi stream
+ * @return code if has an error, 0 otherwise
+ */
+static int lzi_error(IOStream *s){
+ int err = 0;
+ LZIState *state = lzi_state(s);
+ err = state->error;
+ if(err) goto exit;
+ err = IOStream_error(state->io);
+ exit:
+ return err;
+}
+
+/** Close an lzi stream.
+ *
+ * @param s lzi stream to close
+ * @return result of the close
+ */
+static int lzi_close(IOStream *io){
+ int err = 0;
+ LZIState *s = lzi_state(io);
+ if(LZIState_writeable(s)){
+ err = flush_output(s, Z_FINISH);
+ if(err) goto exit;
+ err = write_terminator(s);
+ if(err) goto exit;
+ err = IOStream_flush(s->io);
+ }
+ exit:
+ err = IOStream_close(s->io);
+ set_error(s, err);
+ return err;
+}
+
+/** Free an lzi stream.
+ *
+ * @param s lzi stream
+ */
+static void lzi_free(IOStream *s){
+ LZIState *state = lzi_state(s);
+ IOStream_free(state->io);
+ LZIState_free(state);
+ s->data = NULL;
+}
+
+/** Create an lzi stream for an IOStream.
+ *
+ * @param io stream to wrap
+ * @return new IOStream using f for i/o
+ */
+IOStream *lzi_stream_new(IOStream *io, const char *mode){
+ int err = -ENOMEM;
+ int flags = 0;
+ IOStream *zio = NULL;
+ LZIState *state = NULL;
+
+ zio = ALLOCATE(IOStream);
+ if(!zio) goto exit;
+ err = mode_flags(mode, &flags);
+ if(err) goto exit;
+ state = LZIState_new(io, flags);
+ if(!state) goto exit;
+ err = 0;
+ zio->data = state;
+ zio->methods = &lzi_methods;
+ exit:
+ if(err){
+ if(state) LZIState_free(state);
+ if(zio) deallocate(zio);
+ zio = NULL;
+ }
+ return zio;
+}
+
+/** IOStream version of fdopen().
+ *
+ * @param fd file descriptor
+ * @param flags giving the mode to open in (as for fdopen())
+ * @return new stream for the open file, or NULL if failed
+ */
+IOStream *lzi_stream_fdopen(int fd, const char *mode){
+ int err = -ENOMEM;
+ IOStream *io = NULL, *zio = NULL;
+ io = file_stream_fdopen(fd, mode);
+ if(!io) goto exit;
+ zio = lzi_stream_new(io, mode);
+ if(!io) goto exit;
+ err = 0;
+ exit:
+ if(err){
+ IOStream_free(io);
+ IOStream_free(zio);
+ zio = NULL;
+ }
+ return zio;
+}
+#endif
--- /dev/null
+#/* $Id: lzi_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */
+/*
+ * Copyright (C) 2003 Hewlett-Packard Company.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _SP_LZI_STREAM_H_
+#define _SP_LZI_STREAM_H_
+
+#ifndef __KERNEL__
+#include "iostream.h"
+
+extern IOStream *lzi_stream_new(IOStream *io, const char *mode);
+extern IOStream *lzi_stream_fopen(const char *file, const char *mode);
+extern IOStream *lzi_stream_fdopen(int fd, const char *mode);
+extern IOStream *lzi_stream_io(IOStream *zio);
+
+extern int lzi_stream_plain_bytes(IOStream *io);
+extern int lzi_stream_comp_bytes(IOStream *io);
+extern float lzi_stream_ratio(IOStream *io);
+
+#endif
+#endif /* !_SP_FILE_STREAM_H_ */
--- /dev/null
+/* $Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */
+#define __FILE_ID_INFO "$Id: lzo_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $"
+#include <what.h>
+static char __rcsid[] __attribute__((unused)) = WHAT_ID __FILE_ID_INFO;
+/*
+ * Copyright (C) 2003 Hewlett-Packard Company.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** @file
+ * An IOStream implementation using LZO to provide compression and decompression.
+ * This is designed to provide reasonable compression without output latency.
+ * Flushing an LZO stream flushes all pending data to the underlying stream.
+ * This is essential for stream-based (e.g. networked) applications.
+ *
+ * A compressed data stream is a sequence of blocks.
+ * Each block except the last is the plain data size followed by the compressed data size
+ * and the compressed data. The last block has plain data size zero and omits the rest.
+ * Sizes are 4-byte unsigned in network order. If the compressed size is smaller than
+ * the plain size the block data is compressed, otherwise it is plain (uncompressed).
+ *
+ * This format allows compressed data to be read from a stream without reading
+ * past the logical end of compressed data.
+ *
+ * @author Mike Wray <mike.wray@hpl.hp.com>
+ */
+#ifndef __KERNEL__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include "lzo1x.h"
+
+#include "allocate.h"
+#include "lzo_stream.h"
+#include "file_stream.h"
+#include "marshal.h"
+
+#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZO>%s" fmt, __FUNCTION__, ##args)
+#define wprintf(fmt, args...) fprintf(stderr, "[WARN] LZO>%s" fmt, __FUNCTION__, ##args)
+#define iprintf(fmt, args...) fprintf(stdout, "[INFO] LZO>%s" fmt, __FUNCTION__, ##args)
+#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZO>%s" fmt, __FUNCTION__, ##args)
+
+static int lzo_read(IOStream *s, void *buf, size_t size, size_t count);
+static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count);
+static int lzo_print(IOStream *s, const char *msg, va_list args);
+static int lzo_getc(IOStream *s);
+static int lzo_error(IOStream *s);
+static int lzo_close(IOStream *s);
+static void lzo_free(IOStream *s);
+static int lzo_flush(IOStream *s);
+
+enum {
+ LZO_WRITE = 1,
+ LZO_READ = 2,
+};
+
+/** Methods used by a gzFile* IOStream. */
+static const IOMethods lzo_methods = {
+ read: lzo_read,
+ write: lzo_write,
+ print: lzo_print,
+ getc: lzo_getc,
+ error: lzo_error,
+ close: lzo_close,
+ free: lzo_free,
+ flush: lzo_flush,
+};
+
+//#define PLAIN_SIZE (64 * 1024)
+//#define PLAIN_SIZE (128 * 1024)
+#define PLAIN_SIZE (512 * 1024)
+
+//#define NOCOMPRESS
+
+typedef struct LZOState {
+ /** Flags. */
+ int flags;
+ /** Error indicator. */
+ int error;
+ /** Underlying stream for I/O. */
+ IOStream *io;
+ /** Working memory (only needed for compression, not decompression). */
+ lzo_byte *memory;
+ /** Buffer for plain (uncompressed) data. */
+ lzo_byte *plain;
+ /** Size of the plain buffer. */
+ lzo_uint plain_size;
+ /** Pointer into the plain buffer. */
+ lzo_byte *plain_ptr;
+ /** Number of bytes of plain data available. */
+ lzo_uint plain_n;
+ /** Buffer for compressed data. */
+ lzo_byte *comp;
+ /** Size of the compressed buffer. */
+ lzo_uint comp_size;
+
+ int plain_bytes;
+ int comp_bytes;
+} LZOState;
+
+void LZOState_free(LZOState *z){
+ if(!z) return;
+ deallocate(z->memory);
+ deallocate(z->plain);
+ deallocate(z->comp);
+ deallocate(z);
+}
+
+/** Maximum size of compressed data for the given plain data size.
+ *
+ * @param plain_size size of plain data
+ * @return maximum size of compressed data
+ */
+static int comp_size(int plain_size){
+ return plain_size + (plain_size / 64) + 16 + 3;
+}
+
+static int mode_flags(const char *mode, int *flags){
+ int err = 0;
+ int r=0, w=0;
+ if(!mode){
+ err = -EINVAL;
+ goto exit;
+ }
+ for(; *mode; mode++){
+ if(*mode == 'w') w = 1;
+ if(*mode == 'r') r = 1;
+ }
+ if(r + w != 1){
+ err = -EINVAL;
+ goto exit;
+ }
+ if(r) *flags |= LZO_READ;
+ if(w) *flags |= LZO_WRITE;
+ exit:
+ return err;
+}
+
+/** Get the stream state.
+ *
+ * @param s lzo stream
+ * @return stream state.
+ */
+static inline LZOState * lzo_state(IOStream *s){
+ return s->data;
+}
+
+IOStream *lzo_stream_io(IOStream *s){
+ LZOState *state = lzo_state(s);
+ return state->io;
+}
+
+static inline void set_error(LZOState *state, int err){
+ if(err < 0 && !state->error){
+ state->error = err;
+ }
+}
+
+int lzo_stream_plain_bytes(IOStream *s){
+ LZOState *state = lzo_state(s);
+ return state->plain_bytes;
+}
+
+int lzo_stream_comp_bytes(IOStream *s){
+ LZOState *state = lzo_state(s);
+ return state->comp_bytes;
+}
+
+float lzo_stream_ratio(IOStream *s){
+ LZOState *state = lzo_state(s);
+ float ratio = 0.0;
+ if(state->comp_bytes){
+ ratio = ((float) state->comp_bytes)/((float) state->plain_bytes);
+ }
+ return ratio;
+}
+
+static inline int LZOState_writeable(LZOState *state){
+ return (state->flags & LZO_WRITE) != 0;
+}
+
+static inline int LZOState_readable(LZOState *state){
+ return (state->flags & LZO_READ) != 0;
+}
+
+LZOState * LZOState_new(IOStream *io, int flags){
+ int err = -ENOMEM;
+ LZOState *z = ALLOCATE(LZOState);
+ //dprintf(">\n");
+ if(!z) goto exit;
+ z->io = io;
+ z->flags = flags;
+ if(LZOState_writeable(z)){
+ z->memory = allocate(LZO1X_1_MEM_COMPRESS);
+ if(!z->memory) goto exit;
+ }
+ z->plain_size = PLAIN_SIZE;
+ z->plain = allocate(z->plain_size);
+ if(!z->plain) goto exit;
+ z->plain_ptr = z->plain;
+ z->comp_size = comp_size(z->plain_size);
+ z->comp = allocate(z->comp_size);
+ if(!z->comp) goto exit;
+ err = 0;
+ exit:
+ if(err){
+ LZOState_free(z);
+ z = NULL;
+ }
+ //dprintf("< z=%p\n", z);
+ return z;
+}
+
+static int lzo_compress(LZOState *state){
+ int err = 0;
+ int k, comp_n;
+ //dprintf(">\n");
+ //dprintf(">plain=%p plain_n=%d comp=%p memory=%p\n", state->plain, state->plain_n, state->comp, state->memory);
+ // Compress the plain buffer.
+ err = lzo1x_1_compress(state->plain, state->plain_n,
+ state->comp, &comp_n,
+ state->memory);
+ //dprintf("> err=%d plain_n=%d comp_n=%d\n", err, state->plain_n, comp_n);
+ // Write plain size, compressed size.
+ err = marshal_uint32(state->io, state->plain_n);
+ if(err) goto exit;
+ err = marshal_uint32(state->io, comp_n);
+ if(err) goto exit;
+ //dprintf("> write data...\n");
+ // Write the smaller of the compressed and plain data.
+ if(state->plain_n < comp_n){
+ k = state->plain_n;
+ err = marshal_bytes(state->io, state->plain, state->plain_n);
+ } else {
+ k = comp_n;
+ err = marshal_bytes(state->io, state->comp, comp_n);
+ }
+ if(err) goto exit;
+ // Total output bytes.
+ k+= 8;
+ //dprintf("> wrote %d bytes\n", k);
+ state->plain_bytes += state->plain_n;
+ state->comp_bytes += k;
+ //dprintf("> plain=%d, comp=%d, ratio=%3.2f\n",
+ // state->plain_bytes, state->comp_bytes,
+ // ((float)state->comp_bytes)/((float)state->plain_bytes));
+ // Reset the plain buffer.
+ state->plain_ptr = state->plain;
+ state->plain_n = 0;
+ err = k;
+ exit:
+ //dprintf("< err=%d\n", err);
+ return err;
+}
+
+static int lzo_decompress(LZOState *state){
+ int plain_n, comp_n;
+ int err, k;
+ //dprintf(">\n");
+ err = unmarshal_uint32(state->io, &plain_n);
+ //dprintf("> err=%d plain_n=%d\n", err, plain_n);
+ if(err) goto exit;
+ state->comp_bytes += 4;
+ if(plain_n == 0) goto exit;
+ err = unmarshal_uint32(state->io, &comp_n);
+ //dprintf("> err=%d comp_n=%d\n", err, comp_n);
+ if(err) goto exit;
+ state->comp_bytes += 4;
+ if(plain_n > state->plain_size){
+ err = -EINVAL;
+ goto exit;
+ }
+ if(comp_n > plain_n){
+ //dprintf("> reading plain data %d...\n", plain_n);
+ k = plain_n;
+ err = unmarshal_bytes(state->io, state->plain, plain_n);
+ state->plain_n = plain_n;
+ } else {
+ //dprintf("> reading comp data %d...\n", comp_n);
+ k = comp_n;
+ err = unmarshal_bytes(state->io, state->comp, comp_n);
+ //dprintf("> decompress comp_n=%d\n", comp_n);
+ err = lzo1x_decompress(state->comp, comp_n,
+ state->plain, &state->plain_n,
+ state->memory);
+ //dprintf("> err=%d plain=%d state->plain_n=%d\n", err, plain_n, state->plain_n);
+ if(err != LZO_E_OK || state->plain_n != plain_n){
+ // Bad. Corrupted input.
+ err = -EINVAL;
+ eprintf("> Corrupted!\n");
+ goto exit;
+ }
+ }
+ state->comp_bytes += k;
+ state->plain_bytes += state->plain_n;
+ state->plain_ptr = state->plain;
+ err = k;
+ exit:
+ //dprintf("< err=%d\n", err);
+ return err;
+}
+
+/** Write to the underlying stream using fwrite();
+ *
+ * @param stream destination
+ * @param buf data
+ * @param size size of data elements
+ * @param count number of data elements to write
+ * @return number of data elements written
+ */
+static int lzo_write(IOStream *s, const void *buf, size_t size, size_t count){
+ int err = 0;
+ int n = size * count; // Total number of bytes to write.
+ int chunk; // Size of chunk to write.
+ int remaining; // Number of bytes remaining to write.
+ int space; // Amount of space left in plain buffer.
+ LZOState *state = lzo_state(s);
+#ifdef NOCOMPRESS
+ //dprintf("> buf=%p size=%d count=%d\n", buf, size, count);
+ err = IOStream_write(state->io, buf, size, count);
+ //dprintf("< err=%d\n", err);
+#else
+ //dprintf("> buf=%p size=%d count=%d n=%d\n", buf, size, count, n);
+ remaining = n;
+ space = state->plain_size - state->plain_n;
+ //dprintf("> plain=%p plain_ptr=%p plain_n=%d space=%d\n",
+ // state->plain, state->plain_ptr, state->plain_n, space);
+ while(remaining){
+ chunk = remaining;
+ if(chunk > space) chunk = space;
+ //dprintf("> memcpy %p %p %d\n", state->plain_ptr, buf, chunk);
+ memcpy(state->plain_ptr, buf, chunk);
+ remaining -= chunk;
+ space -= chunk;
+ state->plain_ptr += chunk;
+ state->plain_n += chunk;
+ if(space == 0){
+ // Input buffer is full. Compress and write it.
+ err = lzo_compress(state);
+ if(err < 0) goto exit;
+ space = state->plain_size - state->plain_n;
+ }
+ }
+ err = (size > 1 ? n / size : n);
+ exit:
+ set_error(state, err);
+#endif
+ return err;
+}
+
+
+/** Read from the underlying stream.
+ *
+ * @param stream input
+ * @param buf where to put input
+ * @param size size of data elements
+ * @param count number of data elements to read
+ * @return number of data elements read
+ */
+static int lzo_read(IOStream *s, void *buf, size_t size, size_t count){
+ int err = 0;
+ int k = 0; // Number of (plain) bytes read.
+ int remaining = size * count; // Number of bytes remaining to read.
+ int chunk; // Size of chunk to read.
+ LZOState *state = lzo_state(s);
+#ifdef NOCOMPRESS
+ //dprintf("> buf=%p size=%d count=%d\n", buf, size, count);
+ err = IOStream_read(state->io, buf, size, count);
+ //dprintf("< err=%d\n", err);
+#else
+ if(!(state->flags & LZO_READ)){
+ err = -EINVAL;
+ goto exit;
+ }
+ while(remaining){
+ if(state->plain_n == 0){
+ // No more plain input, decompress some more.
+ err = lzo_decompress(state);
+ if(err < 0) goto exit;
+ // Stop reading if there is no more input.
+ if(err == 0 || state->plain_n == 0) break;
+ }
+ chunk = remaining;
+ if(chunk > state->plain_n) chunk = state->plain_n;
+ memcpy(buf, state->plain_ptr, chunk);
+ k += chunk;
+ buf += chunk;
+ state->plain_ptr += chunk;
+ state->plain_n -= chunk;
+ remaining -= chunk;
+ }
+ err = k;
+ exit:
+ set_error(state, err);
+#endif
+ return err;
+}
+
+/** Print to the underlying stream.
+ * Returns 0 if the formatted output is too big for the internal buffer.
+ *
+ * @param s lzo stream
+ * @param msg format to use
+ * @param args arguments
+ * @return result of the print
+ */
+static int lzo_print(IOStream *s, const char *msg, va_list args){
+ char buf[1024];
+ int buf_n = sizeof(buf);
+ int n;
+ LZOState *state = lzo_state(s);
+ if(!LZOState_writeable(state)){
+ n = -EINVAL;
+ goto exit;
+ }
+ n = vsnprintf(buf, buf_n, (char*)msg, args);
+ if(n < 0) goto exit;
+ if(n > buf_n){
+ n = 0;
+ } else {
+ n = lzo_write(s, buf, 1, n);
+ }
+ exit:
+ return n;
+}
+
+/** Read a character from the underlying stream
+ *
+ * @param s lzo stream
+ * @return character read, IOSTREAM_EOF on end of file (or error)
+ */
+static int lzo_getc(IOStream *s){
+ int err;
+ char c;
+ err = lzo_read(s, &c, 1, 1);
+ if(err < 1) c = EOF;
+ err = (c==EOF ? IOSTREAM_EOF : c);
+ return err;
+}
+
+/** Flush any pending input to the underlying stream.
+ *
+ * @param s lzo stream
+ * @return 0 on success, error code otherwise
+ */
+static int lzo_flush(IOStream *s){
+ int err = 0;
+ LZOState *state = lzo_state(s);
+ //dprintf(">\n");
+#ifdef NOCOMPRESS
+ err = IOStream_flush(state->io);
+#else
+ if(!LZOState_writeable(state)){
+ err = -EINVAL;
+ goto exit;
+ }
+ if(state->plain_n){
+ err = lzo_compress(state);
+ if(err < 0) goto exit;
+ }
+ err = IOStream_flush(state->io);
+ exit:
+ set_error(state, err);
+#endif
+ //dprintf("< err=%d\n", err);
+ return (err < 0 ? err : 0);
+}
+
+/** Check if a stream has an error.
+ *
+ * @param s lzo stream
+ * @return code if has an error, 0 otherwise
+ */
+static int lzo_error(IOStream *s){
+ int err = 0;
+ LZOState *state = lzo_state(s);
+ err = state->error;
+ if(err) goto exit;
+ err = IOStream_error(state->io);
+ exit:
+ return err;
+}
+
+int lzo_stream_finish(IOStream *s){
+ int err = 0;
+ LZOState *state = lzo_state(s);
+ if(!LZOState_writeable(state)){
+ err = -EINVAL;
+ goto exit;
+ }
+ err = lzo_flush(s);
+ if(err < 0) goto exit;
+ err = marshal_int32(state->io, 0);
+ exit:
+ return err;
+}
+
+/** Close an lzo stream.
+ *
+ * @param s lzo stream to close
+ * @return result of the close
+ */
+static int lzo_close(IOStream *s){
+ int err = 0;
+ LZOState *state = lzo_state(s);
+#ifdef NOCOMPRESS
+ err = IOStream_close(state->io);
+#else
+ if(LZOState_writeable(state)){
+ err = lzo_stream_finish(s);
+ }
+ err = IOStream_close(state->io);
+ set_error(state, err);
+#endif
+ return err;
+}
+
+/** Free an lzo stream.
+ *
+ * @param s lzo stream
+ */
+static void lzo_free(IOStream *s){
+ LZOState *state = lzo_state(s);
+ IOStream_free(state->io);
+ LZOState_free(state);
+ s->data = NULL;
+}
+
+/** Create an lzo stream for an IOStream.
+ *
+ * @param io stream to wrap
+ * @return new IOStream using f for i/o
+ */
+IOStream *lzo_stream_new(IOStream *io, const char *mode){
+ int err = -ENOMEM;
+ int flags = 0;
+ IOStream *zio = NULL;
+ LZOState *state = NULL;
+
+ zio = ALLOCATE(IOStream);
+ if(!zio) goto exit;
+ err = mode_flags(mode, &flags);
+ if(err) goto exit;
+ state = LZOState_new(io, flags);
+ if(!state) goto exit;
+ err = 0;
+ zio->data = state;
+ zio->methods = &lzo_methods;
+ exit:
+ if(err){
+ if(state) LZOState_free(state);
+ if(zio) deallocate(zio);
+ zio = NULL;
+ }
+ return zio;
+}
+
+/** IOStream version of fdopen().
+ *
+ * @param fd file descriptor
+ * @param flags giving the mode to open in (as for fdopen())
+ * @return new stream for the open file, or NULL if failed
+ */
+IOStream *lzo_stream_fdopen(int fd, const char *mode){
+ int err = -ENOMEM;
+ IOStream *io = NULL, *zio = NULL;
+ io = file_stream_fdopen(fd, mode);
+ if(!io) goto exit;
+ zio = lzo_stream_new(io, mode);
+ if(!io) goto exit;
+ err = 0;
+ exit:
+ if(err){
+ IOStream_free(io);
+ IOStream_free(zio);
+ zio = NULL;
+ }
+ return zio;
+}
+#endif
--- /dev/null
+#/* $Id: lzo_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */
+/*
+ * Copyright (C) 2003 Hewlett-Packard Company.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _SP_LZO_STREAM_H_
+#define _SP_LZO_STREAM_H_
+
+#ifndef __KERNEL__
+#include "iostream.h"
+
+extern IOStream *lzo_stream_new(IOStream *io, const char *mode);
+extern IOStream *lzo_stream_fopen(const char *file, const char *mode);
+extern IOStream *lzo_stream_fdopen(int fd, const char *mode);
+extern IOStream *lzo_stream_io(IOStream *zio);
+
+extern int lzo_stream_plain_bytes(IOStream *io);
+extern int lzo_stream_comp_bytes(IOStream *io);
+extern float lzo_stream_ratio(IOStream *io);
+
+#endif
+#endif /* !_SP_FILE_STREAM_H_ */
--- /dev/null
+#include <errno.h>
+#include "sys_net.h"
+#include "allocate.h"
+#include "marshal.h"
+
+#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
+#define wprintf(fmt, args...) IOStream_print(iostderr, "[WARN] %s" fmt, __FUNCTION__, ##args)
+#define iprintf(fmt, args...) IOStream_print(iostdout, "[INFO] %s" fmt, __FUNCTION__, ##args)
+#define eprintf(fmt, args...) IOStream_print(iostderr, "[ERROR] %s" fmt, __FUNCTION__, ##args)
+
+
+#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof((ary)[0]))
+
+/* Messages are coded as msgid followed by message fields.
+ * Initial message on any channel is hello - so can check version
+ * compatibility.
+ *
+ * char* -> uint16_t:n <n bytes>
+ * ints/uints go as suitable number of bytes (e.g. uint16_t is 2 bytes).
+ * optional fields go as '1' <val> or '0' (the 0/1 is 1 byte).
+ * lists go as ('1' <elt>)* '0'
+ */
+
+int marshal_flush(IOStream *io){
+ int err = 0;
+ err = IOStream_flush(io);
+ return err;
+}
+
+int marshal_bytes(IOStream *io, void *s, uint32_t s_n){
+ int err = 0;
+ int n;
+ n = IOStream_write(io, s, s_n);
+ if(n < 0){
+ err = n;
+ } else if (n < s_n){
+ wprintf("> Wanted %d, got %d\n", s_n, n);
+ err = -EIO;
+ }
+ return err;
+}
+
+int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n){
+ int err = 0;
+ int n;
+ //dprintf("> s_n=%d\n", s_n);
+ n = IOStream_read(io, s, s_n);
+ //dprintf("> n=%d\n", n);
+ if(n < 0){
+ err = n;
+ } else if(n < s_n){
+ wprintf("> Wanted %d, got %d\n", s_n, n);
+ err = -EIO;
+ }
+ //dprintf("< err=%d\n", err);
+ return err;
+}
+
+int marshal_uint8(IOStream *io, uint8_t x){
+ return marshal_bytes(io, &x, sizeof(x));
+}
+
+int unmarshal_uint8(IOStream *io, uint8_t *x){
+ return unmarshal_bytes(io, x, sizeof(*x));
+}
+
+int marshal_uint16(IOStream *io, uint16_t x){
+ x = htons(x);
+ return marshal_bytes(io, &x, sizeof(x));
+}
+
+int unmarshal_uint16(IOStream *io, uint16_t *x){
+ int err = 0;
+ err = unmarshal_bytes(io, x, sizeof(*x));
+ *x = ntohs(*x);
+ return err;
+}
+
+int marshal_int32(IOStream *io, int32_t x){
+ int err = 0;
+ //dprintf("> x=%d\n", x);
+ x = htonl(x);
+ err = marshal_bytes(io, &x, sizeof(x));
+ //dprintf("< err=%d\n", err);
+ return err;
+}
+
+int unmarshal_int32(IOStream *io, int32_t *x){
+ int err = 0;
+ //dprintf(">\n");
+ err = unmarshal_bytes(io, x, sizeof(*x));
+ *x = ntohl(*x);
+ //dprintf("< err=%d x=%d\n", err, *x);
+ return err;
+}
+
+int marshal_uint32(IOStream *io, uint32_t x){
+ int err = 0;
+ //dprintf("> x=%u\n", x);
+ x = htonl(x);
+ err = marshal_bytes(io, &x, sizeof(x));
+ //dprintf("< err=%d\n", err);
+ return err;
+}
+
+int unmarshal_uint32(IOStream *io, uint32_t *x){
+ int err = 0;
+ //dprintf(">\n");
+ err = unmarshal_bytes(io, x, sizeof(*x));
+ *x = ntohl(*x);
+ //dprintf("< err=%d x=%u\n", err, *x);
+ return err;
+}
+
+int marshal_uint64(IOStream *io, uint64_t x){
+ int err;
+ err = marshal_uint32(io, (uint32_t) ((x >> 32) & 0xffffffff));
+ if(err) goto exit;
+ err = marshal_uint32(io, (uint32_t) ( x & 0xffffffff));
+ exit:
+ return err;
+}
+
+int unmarshal_uint64(IOStream *io, uint64_t *x){
+ int err = 0;
+ uint32_t hi, lo;
+ err = unmarshal_uint32(io, &hi);
+ if(err) goto exit;
+ err = unmarshal_uint32(io, &lo);
+ *x = (((uint64_t) hi) << 32) | lo;
+ exit:
+ return err;
+}
+
+int marshal_net16(IOStream *io, net16_t x){
+ return marshal_bytes(io, &x, sizeof(x));
+}
+
+int unmarshal_net16(IOStream *io, net16_t *x){
+ int err = 0;
+ err = unmarshal_bytes(io, x, sizeof(*x));
+ return err;
+}
+
+int marshal_net32(IOStream *io, net32_t x){
+ return marshal_bytes(io, &x, sizeof(x));
+}
+
+int unmarshal_net32(IOStream *io, net32_t *x){
+ int err = 0;
+ err = unmarshal_bytes(io, x, sizeof(*x));
+ return err;
+}
+
+int marshal_string(IOStream *io, char *s, uint32_t s_n){
+ int err;
+ //dprintf("> s=%s\n", s);
+ err = marshal_uint32(io, s_n);
+ if(err) goto exit;
+ err = marshal_bytes(io, s, s_n);
+ exit:
+ //dprintf("< err=%d\n", err);
+ return err;
+}
+
+int unmarshal_string(IOStream *io, char *s, uint32_t s_n){
+ int err = 0, val_n = 0;
+ //dprintf(">\n");
+ err = unmarshal_uint32(io, &val_n);
+ if(err) goto exit;
+ if(val_n >= s_n){
+ err = -EINVAL;
+ goto exit;
+ }
+ err = unmarshal_bytes(io, s, val_n);
+ if(err) goto exit;
+ s[val_n] = '\0';
+ exit:
+ //dprintf("< err=%d s=%s\n", err, s);
+ return err;
+}
+
+int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n){
+ int err = 0, val_n = 0;
+ char *val = NULL;
+ //dprintf(">\n");
+ err = unmarshal_uint32(io, &val_n);
+ if(err) goto exit;
+ val = allocate(val_n + 1);
+ if(!val){
+ err = -ENOMEM;
+ goto exit;
+ }
+ err = unmarshal_bytes(io, val, val_n);
+ if(err) goto exit;
+ val[val_n] = '\0';
+ exit:
+ if(err){
+ if(val) deallocate(val);
+ val = NULL;
+ val_n = 0;
+ }
+ *s = val;
+ if(s_n) *s_n = val_n;
+ //dprintf("< err=%d s=%s\n", err, *s);
+ return err;
+}
--- /dev/null
+/* $Id: marshal.h,v 1.1 2003/10/17 15:48:43 mjw Exp $ */
+#ifndef _SP_MARSHAL_H_
+#define _SP_MARSHAL_H_
+
+#include "iostream.h"
+
+/** A 16-bit uint in network order, e.g. a port number. */
+typedef uint16_t net16_t;
+
+/** A 32-bit uint in network order, e.g. an IP address. */
+typedef uint32_t net32_t;
+
+extern int marshal_flush(IOStream *io);
+
+extern int marshal_bytes(IOStream *io, void *s, uint32_t s_n);
+extern int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n);
+
+extern int marshal_uint8(IOStream *io, uint8_t x);
+extern int unmarshal_uint8(IOStream *io, uint8_t *x);
+
+extern int marshal_uint16(IOStream *io, uint16_t x);
+extern int unmarshal_uint16(IOStream *io, uint16_t *x);
+
+extern int marshal_uint32(IOStream *io, uint32_t x);
+extern int unmarshal_uint32(IOStream *io, uint32_t *x);
+
+extern int marshal_int32(IOStream *io, int32_t x);
+extern int unmarshal_int32(IOStream *io, int32_t *x);
+
+extern int marshal_uint64(IOStream *io, uint64_t x);
+extern int unmarshal_uint64(IOStream *io, uint64_t *x);
+
+extern int marshal_net16(IOStream *io, net16_t x);
+extern int unmarshal_net16(IOStream *io, net16_t *x);
+
+extern int marshal_net32(IOStream *io, net32_t x);
+extern int unmarshal_net32(IOStream *io, net32_t *x);
+
+extern int marshal_string(IOStream *io, char *s, uint32_t s_n);
+extern int unmarshal_string(IOStream *io, char *s, uint32_t s_n);
+extern int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n);
+
+#endif /* ! _SP_MARSHAL_H_ */
--- /dev/null
+/* $Id: socket_stream.c,v 1.9 2004/03/05 14:45:34 mjw Exp $ */
+/*
+ * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** @file
+ * An IOStream implementation using sockets.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include "allocate.h"
+#include "socket_stream.h"
+
+#define MODULE_NAME "sock"
+#define DEBUG 0
+//#undef DEBUG
+#include "debug.h"
+
+static int socket_read(IOStream *s, void *buf, size_t n);
+static int socket_write(IOStream *s, const void *buf, size_t n);
+static int socket_error(IOStream *s);
+static int socket_close(IOStream *s);
+static void socket_free(IOStream *s);
+static int socket_flush(IOStream *s);
+
+/** Methods used by a socket IOStream. */
+static const IOMethods socket_methods = {
+ read: socket_read,
+ write: socket_write,
+ error: socket_error,
+ close: socket_close,
+ free: socket_free,
+ flush: socket_flush,
+};
+
+/** Get the socket data.
+ *
+ * @param io socket stream
+ * @return data
+ */
+static inline SocketData * socket_data(IOStream *io){
+ return (SocketData *)io->data;
+}
+
+/** Test if a stream is a socket stream.
+ *
+ * @param io stream
+ * @return 0 if a socket stream, -EINVAL if not
+ */
+int socket_stream_check(IOStream *io){
+ return (io && io->methods == &socket_methods ? 0 : -EINVAL);
+}
+
+/** Get the data for a socket stream.
+ *
+ * @param io stream
+ * @param data return value for the data
+ * @return 0 if a socket stream, -EINVAL if not
+ */
+int socket_stream_data(IOStream *io, SocketData **data){
+ int err = socket_stream_check(io);
+ if(err){
+ *data = NULL;
+ } else {
+ *data = socket_data(io);
+ }
+ return err;
+}
+
+/** Set the destination address for a socket stream.
+ *
+ * @param io stream
+ * @param addr address
+ * @return 0 if a socket stream, -EINVAL if not
+ */
+int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr){
+ int err = 0;
+ SocketData *data = NULL;
+ err = socket_stream_data(io, &data);
+ if(!err){
+ data->daddr = *addr;
+ }
+ return err;
+}
+
+/** Set the send flags for a socket stream.
+ *
+ * @param io stream
+ * @param flags flags
+ * @return 0 if a socket stream, -EINVAL if not
+ */
+int socket_stream_set_flags(IOStream *io, int flags){
+ int err = 0;
+ SocketData *data = NULL;
+ err = socket_stream_data(io, &data);
+ if(!err){
+ data->flags = flags;
+ }
+ return err;
+}
+
+/** Write to the underlying socket using sendto.
+ *
+ * @param stream input
+ * @param buf where to put input
+ * @param n number of bytes to write
+ * @return number of bytes written
+ */
+static int socket_write(IOStream *s, const void *buf, size_t n){
+ SocketData *data = socket_data(s);
+ struct sockaddr *daddr = (struct sockaddr *)&data->daddr;
+ socklen_t daddr_n = sizeof(data->daddr);
+ int k;
+ dprintf("> sock=%d addr=%s:%d n=%d\n",
+ data->fd, inet_ntoa(data->daddr.sin_addr), ntohs(data->daddr.sin_port), n);
+ if(0){
+ struct sockaddr_in self = {};
+ socklen_t self_n;
+ getsockname(data->fd, (struct sockaddr *)&self, &self_n);
+ dprintf("> sockname sock=%d %s:%d\n",
+ data->fd, inet_ntoa(self.sin_addr), ntohs(self.sin_port));
+ }
+ k = sendto(data->fd, buf, n, data->flags, daddr, daddr_n);
+ dprintf("> sendto=%d\n", k);
+ return k;
+}
+
+/** Read from the underlying stream using recv();
+ *
+ * @param stream input
+ * @param buf where to put input
+ * @param n number of bytes to read
+ * @return number of bytes read
+ */
+static int socket_read(IOStream *s, void *buf, size_t n){
+ SocketData *data = socket_data(s);
+ int k;
+ struct sockaddr *saddr = (struct sockaddr *)&data->saddr;
+ socklen_t saddr_n = sizeof(data->saddr);
+ k = recvfrom(data->fd, buf, n, data->flags, saddr, &saddr_n);
+ return k;
+}
+
+/** Print to the underlying socket.
+ *
+ * @param s socket stream
+ * @param msg format to use
+ * @param args arguments
+ * @return result of the print
+ */
+static int socket_print(IOStream *s, const char *msg, va_list args){
+ SocketData *data = socket_data(s);
+ int n;
+ n = vsnprintf(data->buf, data->buf_n - 1, msg, args);
+ if(0 < n && n < data->buf_n){
+ socket_write(s, data->buf, n);
+ }
+ return n;
+}
+
+/** Read a character from the underlying socket
+ *
+ * @param s socket stream
+ * @return character read, IOSTREAM_EOF on end of socket (or error)
+ */
+static int socket_getc(IOStream *s){
+ char b;
+ int n, c;
+ n = socket_read(s, &b, 1);
+ c = (n <= 0 ? IOSTREAM_EOF : b);
+ return c;
+}
+
+/** Flush the socket (no-op).
+ *
+ * @param s socket stream
+ * @return 0 on success, error code otherwise
+ */
+static int socket_flush(IOStream *s){
+ return 0;
+}
+
+/** Check if a socket stream has an error (no-op).
+ *
+ * @param s socket stream
+ * @return 1 if has an error, 0 otherwise
+ */
+static int socket_error(IOStream *s){
+ // Read SOL_SOCKET/SO_ERROR ?
+ return 0;
+}
+
+/** Close a socket stream.
+ *
+ * @param s socket stream to close
+ * @return result of the close
+ */
+static int socket_close(IOStream *s){
+ SocketData *data = socket_data(s);
+ return close(data->fd);
+}
+
+/** Free a socket stream.
+ *
+ * @param s socket stream
+ */
+static void socket_free(IOStream *s){
+ SocketData *data = socket_data(s);
+ deallocate(data);
+}
+
+/** Create an IOStream for a socket.
+ *
+ * @param fd socket to wtap
+ * @return new IOStream using fd for i/o
+ */
+IOStream *socket_stream_new(int fd){
+ int err = -ENOMEM;
+ IOStream *io = NULL;
+ SocketData *data = NULL;
+
+ io = ALLOCATE(IOStream);
+ if(!io) goto exit;
+ io->methods = &socket_methods;
+ data = ALLOCATE(SocketData);
+ if(!data) goto exit;
+ io->data = data;
+ data->fd = fd;
+ data->buf_n = sizeof(data->buf);
+ err = 0;
+ exit:
+ if(err){
+ if(io){
+ if(data) deallocate(data);
+ deallocate(io);
+ io = NULL;
+ }
+ }
+ return io;
+}
+
--- /dev/null
+/* $Id: socket_stream.h,v 1.2 2004/03/04 17:38:13 mjw Exp $ */
+/*
+ * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XEN_LIB_SOCKET_STREAM_H_
+#define _XEN_LIB_SOCKET_STREAM_H_
+
+#ifndef __KERNEL__
+#include "iostream.h"
+#include <stdio.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/** Data associated with a socket stream. */
+typedef struct SocketData {
+ /** The socket file descriptor. */
+ int fd;
+ /** Source address from last read (recvfrom). */
+ struct sockaddr_in saddr;
+ /** Destination address for writes (sendto). */
+ struct sockaddr_in daddr;
+ /** Write flags (sendto). */
+ int flags;
+ /** Buffer size. */
+ int buf_n;
+ /** Buffer for formatted printing. */
+ char buf[1024];
+} SocketData;
+
+extern IOStream *socket_stream_new(int fd);
+extern int socket_stream_data(IOStream *io, SocketData **data);
+extern int socket_stream_check(IOStream *io);
+extern int socket_stream_set_addr(IOStream *io, struct sockaddr_in *addr);
+extern int socket_stream_set_flags(IOStream *io, int flags);
+
+#endif
+#endif /* !_XEN_LIB_SOCKET_STREAM_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2001, 2002 Hewlett-Packard Company.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** @file
+ * IOStream subtype for input and output to strings.
+ * Usable from user or kernel code (with __KERNEL__ defined).
+ */
+
+#include "sys_string.h"
+#include "string_stream.h"
+#include "allocate.h"
+
+static int string_print(IOStream *io, const char *msg, va_list args);
+static int string_getc(IOStream *io);
+static int string_error(IOStream *io);
+static int string_close(IOStream *io);
+static void string_free(IOStream *io);
+
+/** Methods for a string stream. */
+static IOMethods string_methods = {
+ //print: string_print,
+ //getc: string_getc,
+ error: string_error,
+ close: string_close,
+ free: string_free,
+};
+
+/** Get the string stream state.
+ *
+ * @param io string stream
+ * @return state
+ */
+static inline StringData *get_string_data(IOStream *io){
+ return (StringData*)io->data;
+}
+
+/** Read a character from a string stream.
+ *
+ * @param io string stream
+ * @return character read, IOSTREAM_EOF if no more input
+ */
+static int string_getc(IOStream *io){
+ StringData *data = get_string_data(io);
+ int c = IOSTREAM_EOF;
+ char *s = data->in;
+
+ if(s && s < data->end){
+ c = (unsigned)*s;
+ data->in = s+1;
+ }
+ return c;
+}
+
+/** Print to a string stream.
+ * Formats the data to an internal buffer and prints it.
+ * The formatted data must fit into the internal buffer.
+ *
+ * @param io string stream
+ * @param format print format
+ * @param args print arguments
+ * @return result of the print
+ */
+static int string_print(IOStream *io, const char *msg, va_list args){
+ StringData *data = get_string_data(io);
+ int k = data->end - data->out;
+ int n = vsnprintf(data->out, k, (char*)msg, args);
+ if(n < 0 || n > k ){
+ n = k;
+ IOStream_close(io);
+ } else {
+ data->out += n;
+ }
+ return n;
+}
+
+/** Test if a string stream has an error.
+ *
+ * @param io string stream
+ * @return 0 if ok, error code otherwise
+ */
+static int string_error(IOStream *io){
+ StringData *data = get_string_data(io);
+ return data->out == NULL;
+}
+
+/** Close a string stream.
+ *
+ * @param io string stream
+ * @return 0
+ */
+static int string_close(IOStream *io){
+ StringData *data = get_string_data(io);
+ data->in = NULL;
+ data->out = NULL;
+ return 0;
+}
+
+/** Free a string stream.
+ * The stream must have been allocated, not statically created.
+ * The stream state is freed, but the underlying string is not.
+ *
+ * @param io string stream
+ */
+static void string_free(IOStream *io){
+ StringData *data = get_string_data(io);
+ zero(data, sizeof(*data));
+ deallocate(data);
+}
+
+/** Get the methods to use for a string stream.
+ *
+ * @return methods
+ */
+IOMethods *string_stream_get_methods(void){
+ return &string_methods;
+}
+
+/** Initialise a string stream, usually from static data.
+ *
+ * @param io address of IOStream to fill in
+ * @param data address of StringData to fill in
+ * @param s string to use
+ * @param n length of the string
+ */
+void string_stream_init(IOStream *io, StringData *data, char *s, int n){
+ if(data && io){
+ zero(data, sizeof(*data));
+ data->string = (char*)s;
+ data->in = data->string;
+ data->out = data->string;
+ data->size = n;
+ data->end = data->string + n;
+ zero(io, sizeof(*io));
+ io->methods = &string_methods;
+ io->data = data;
+ }
+}
+
+/** Allocate and initialise a string stream.
+ *
+ * @param s string to use
+ * @param n length of the string
+ * @return new stream (free using IOStream_free)
+ */
+IOStream *string_stream_new(char *s, int n){
+ int ok = 0;
+ StringData *data = ALLOCATE(StringData);
+ IOStream *io = ALLOCATE(IOStream);
+ if(data && io){
+ ok = 1;
+ string_stream_init(io, data, s, n);
+ }
+ if(!ok){
+ deallocate(data);
+ deallocate(io);
+ io = NULL;
+ }
+ return io;
+}
--- /dev/null
+/* $Id: string_stream.h,v 1.1 2003/08/22 14:25:48 mjw Exp $ */
+/*
+ * Copyright (C) 2001, 2002 Hewlett-Packard Company.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _SP_STRING_STREAM_H_
+#define _SP_STRING_STREAM_H_
+
+#include "iostream.h"
+
+/** Internal state for a string stream.
+ * Exposed here so that string streams can be statically created, using
+ * string_stream_init().
+ */
+typedef struct {
+ /** The string used for input and ouput. */
+ char *string;
+ /** Output pointer. */
+ char *out;
+ /** Input pointer. */
+ char *in;
+ /** Length of string. */
+ int size;
+ /** End marker. */
+ char *end;
+} StringData;
+
+extern IOMethods *string_stream_get_methods(void);
+extern IOStream *string_stream_new(char *s, int n);
+extern void string_stream_init(IOStream *stream, StringData *data, char *s, int n);
+
+#endif /* !_SP_STRING_STREAM_H_ */
--- /dev/null
+/*
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+#include "sys_string.h"
+#include "lexis.h"
+#include "sys_net.h"
+#include "hash_table.h"
+#include "sxpr.h"
+
+#include <errno.h>
+#undef free
+
+/** @file
+ * General representation of sxprs.
+ * Includes print, equal, and free functions for the sxpr types.
+ *
+ * Zero memory containing an Sxpr will have the value ONONE - this is intentional.
+ * When a function returning an sxpr cannot allocate memory we return ONOMEM.
+ *
+ */
+
+static int atom_print(IOStream *io, Sxpr obj, unsigned flags);
+static int atom_equal(Sxpr x, Sxpr y);
+static void atom_free(Sxpr obj);
+
+static int string_print(IOStream *io, Sxpr obj, unsigned flags);
+static int string_equal(Sxpr x, Sxpr y);
+static void string_free(Sxpr obj);
+
+static int cons_print(IOStream *io, Sxpr obj, unsigned flags);
+static int cons_equal(Sxpr x, Sxpr y);
+static void cons_free(Sxpr obj);
+
+static int null_print(IOStream *io, Sxpr obj, unsigned flags);
+static int none_print(IOStream *io, Sxpr obj, unsigned flags);
+static int int_print(IOStream *io, Sxpr obj, unsigned flags);
+static int bool_print(IOStream *io, Sxpr obj, unsigned flags);
+
+/** Type definitions. */
+static SxprType types[1024] = {
+ [T_NONE] { type: T_NONE, name: "none", print: none_print },
+ [T_NULL] { type: T_NULL, name: "null", print: null_print },
+ [T_UINT] { type: T_UINT, name: "int", print: int_print, },
+ [T_BOOL] { type: T_BOOL, name: "bool", print: bool_print, },
+ [T_ATOM] { type: T_ATOM, name: "atom", print: atom_print,
+ pointer: TRUE,
+ free: atom_free,
+ equal: atom_equal,
+ },
+ [T_STRING] { type: T_STRING, name: "string", print: string_print,
+ pointer: TRUE,
+ free: string_free,
+ equal: string_equal,
+ },
+ [T_CONS] { type: T_CONS, name: "cons", print: cons_print,
+ pointer: TRUE,
+ free: cons_free,
+ equal: cons_equal,
+ },
+};
+
+/** Number of entries in the types array. */
+static int type_sup = sizeof(types)/sizeof(types[0]);
+
+/** Get the type definition for a given type code.
+ *
+ * @param ty type code
+ * @return type definition or null
+ */
+SxprType *get_sxpr_type(int ty){
+ if(0 <= ty && ty < type_sup){
+ return types+ty;
+ }
+ return NULL;
+}
+
+/** The default print function.
+ *
+ * @param io stream to print to
+ * @param x sxpr to print
+ * @param flags print flags
+ * @return number of bytes written on success
+ */
+int default_print(IOStream *io, Sxpr x, unsigned flags){
+ return IOStream_print(io, "#<%u %lu>\n", get_type(x), get_ul(x));
+}
+
+/** The default equal function.
+ * Uses eq().
+ *
+ * @param x sxpr to compare
+ * @param y sxpr to compare
+ * @return 1 if equal, 0 otherwise
+ */
+int default_equal(Sxpr x, Sxpr y){
+ return eq(x, y);
+}
+
+/** General sxpr print function.
+ * Prints an sxpr on a stream using the print function for the sxpr type.
+ * Printing is controlled by flags from the PrintFlags enum.
+ * If PRINT_TYPE is in the flags the sxpr type is printed before the sxpr
+ * (for debugging).
+ *
+ * @param io stream to print to
+ * @param x sxpr to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+int objprint(IOStream *io, Sxpr x, unsigned flags){
+ SxprType *def = get_sxpr_type(get_type(x));
+ ObjPrintFn *print_fn = (def && def->print ? def->print : default_print);
+ int k = 0;
+ if(!io) return k;
+ if(flags & PRINT_TYPE){
+ k += IOStream_print(io, "%s:", def->name);
+ }
+ k += print_fn(io, x, flags);
+ return k;
+}
+
+/** General sxpr free function.
+ * Frees an sxpr using the free function for its type.
+ * Free functions must recursively free any subsxprs.
+ * If no function is defined then the default is to
+ * free sxprs whose type has pointer true.
+ * Sxprs must not be used after freeing.
+ *
+ * @param x sxpr to free
+ */
+void objfree(Sxpr x){
+ SxprType *def = get_sxpr_type(get_type(x));
+
+ if(def){
+ if(def->free){
+ def->free(x);
+ } else if (def->pointer){
+ hfree(x);
+ }
+ }
+}
+
+/** General sxpr equality function.
+ * Compares x and y using the equal function for x.
+ * Uses default_equal() if x has no equal function.
+ *
+ * @param x sxpr to compare
+ * @param y sxpr to compare
+ * @return 1 if equal, 0 otherwise
+ */
+int objequal(Sxpr x, Sxpr y){
+ SxprType *def = get_sxpr_type(get_type(x));
+ ObjEqualFn *equal_fn = (def && def->equal ? def->equal : default_equal);
+ return equal_fn(x, y);
+}
+
+/** Search for a key in an alist.
+ * An alist is a list of conses, where the cars
+ * of the conses are the keys. Compares keys using equality.
+ *
+ * @param k key
+ * @param l alist to search
+ * @return first element of l with car k, or ONULL
+ */
+Sxpr assoc(Sxpr k, Sxpr l){
+ for( ; CONSP(l) ; l = CDR(l)){
+ Sxpr x = CAR(l);
+ if(CONSP(x) && objequal(k, CAR(x))){
+ return x;
+ }
+ }
+ return ONULL;
+}
+
+/** Search for a key in an alist.
+ * An alist is a list of conses, where the cars
+ * of the conses are the keys. Compares keys using eq.
+ *
+ * @param k key
+ * @param l alist to search
+ * @return first element of l with car k, or ONULL
+ */
+Sxpr assocq(Sxpr k, Sxpr l){
+ for( ; CONSP(l); l = CDR(l)){
+ Sxpr x = CAR(l);
+ if(CONSP(x) && eq(k, CAR(x))){
+ return x;
+ }
+ }
+ return ONULL;
+}
+
+/** Add a new key and value to an alist.
+ *
+ * @param k key
+ * @param l value
+ * @param l alist
+ * @return l with the new cell added to the front
+ */
+Sxpr acons(Sxpr k, Sxpr v, Sxpr l){
+ Sxpr x, y;
+ x = cons_new(k, v);
+ if(NOMEMP(x)) return x;
+ y = cons_new(x, l);
+ if(NOMEMP(y)) cons_free_cells(x);
+ return y;
+}
+
+/** Test if a list contains an element.
+ * Uses sxpr equality.
+ *
+ * @param l list
+ * @param x element to look for
+ * @return a tail of l with x as car, or ONULL
+ */
+Sxpr cons_member(Sxpr l, Sxpr x){
+ for( ; CONSP(l) && !eq(x, CAR(l)); l = CDR(l)){}
+ return l;
+}
+
+/** Test if a list contains an element satisfying a test.
+ * The test function is called with v and an element of the list.
+ *
+ * @param l list
+ * @param test_fn test function to use
+ * @param v value for first argument to the test
+ * @return a tail of l with car satisfying the test, or 0
+ */
+Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
+ for( ; CONSP(l) && !test_fn(v, CAR(l)); l = CDR(l)){ }
+ return l;
+}
+
+/** Test if the elements of list 't' are a subset of the elements
+ * of list 's'. Element order is not significant.
+ *
+ * @param s element list to check subset of
+ * @param t element list to check if is a subset
+ * @return 1 if is a subset, 0 otherwise
+ */
+int cons_subset(Sxpr s, Sxpr t){
+ for( ; CONSP(t); t = CDR(t)){
+ if(!CONSP(cons_member(s, CAR(t)))){
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/** Test if two lists have equal sets of elements.
+ * Element order is not significant.
+ *
+ * @param s list to check
+ * @param t list to check
+ * @return 1 if equal, 0 otherwise
+ */
+int cons_set_equal(Sxpr s, Sxpr t){
+ return cons_subset(s, t) && cons_subset(t, s);
+}
+
+#ifdef USE_GC
+/*============================================================================*/
+/* The functions inside this ifdef are only safe if GC is used.
+ * Otherwise they may leak memory.
+ */
+
+/** Remove an element from a list (GC only).
+ * Uses sxpr equality and removes all instances, even
+ * if there are more than one.
+ *
+ * @param l list to remove elements from
+ * @param x element to remove
+ * @return modified input list
+ */
+Sxpr cons_remove(Sxpr l, Sxpr x){
+ return cons_remove_if(l, eq, x);
+}
+
+/** Remove elements satisfying a test (GC only).
+ * The test function is called with v and an element of the set.
+ *
+ * @param l list to remove elements from
+ * @param test_fn function to use to decide if an element should be removed
+ * @return modified input list
+ */
+Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
+ Sxpr prev = ONULL, elt, next;
+
+ for(elt = l; CONSP(elt); elt = next){
+ next = CDR(elt);
+ if(test_fn(v, CAR(elt))){
+ if(NULLP(prev)){
+ l = next;
+ } else {
+ CDR(prev) = next;
+ }
+ }
+ }
+ return l;
+}
+
+/** Set the value for a key in an alist (GC only).
+ * If the key is present, changes the value, otherwise
+ * adds a new cell.
+ *
+ * @param k key
+ * @param v value
+ * @param l alist
+ * @return modified or extended list
+ */
+Sxpr setf(Sxpr k, Sxpr v, Sxpr l){
+ Sxpr e = assoc(k, l);
+ if(NULLP(e)){
+ l = acons(k, v, l);
+ } else {
+ CAR(CDR(e)) = v;
+ }
+ return l;
+}
+/*============================================================================*/
+#endif /* USE_GC */
+
+/** Create a new atom with the given name.
+ *
+ * @param name the name
+ * @return new atom
+ */
+Sxpr atom_new(char *name){
+ Sxpr n, obj = ONOMEM;
+
+ n = string_new(name);
+ if(NOMEMP(n)) goto exit;
+ obj = HALLOC(ObjAtom, T_ATOM);
+ if(NOMEMP(obj)) goto exit;
+ OBJ_ATOM(obj)->name = n;
+ exit:
+ return obj;
+}
+
+/** Free an atom.
+ *
+ * @param obj to free
+ */
+void atom_free(Sxpr obj){
+ // Interned atoms are shared, so do not free.
+ if(OBJ_ATOM(obj)->interned) return;
+ objfree(OBJ_ATOM(obj)->name);
+ hfree(obj);
+}
+
+/** Print an atom. Prints the atom name.
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes printed
+ */
+int atom_print(IOStream *io, Sxpr obj, unsigned flags){
+ //return string_print(io, OBJ_ATOM(obj)->name, (flags | PRINT_RAW));
+ return string_print(io, OBJ_ATOM(obj)->name, flags);
+}
+
+/** Atom equality.
+ *
+ * @param x to compare
+ * @param y to compare
+ * @return 1 if equal, 0 otherwise
+ */
+int atom_equal(Sxpr x, Sxpr y){
+ int ok;
+ ok = eq(x, y);
+ if(ok) goto exit;
+ ok = ATOMP(y) && string_equal(OBJ_ATOM(x)->name, OBJ_ATOM(y)->name);
+ if(ok) goto exit;
+ ok = STRINGP(y) && string_equal(OBJ_ATOM(x)->name, y);
+ exit:
+ return ok;
+}
+
+/** Get the name of an atom.
+ *
+ * @param obj atom
+ * @return name
+ */
+char * atom_name(Sxpr obj){
+ return string_string(OBJ_ATOM(obj)->name);
+}
+
+/** Get the C string from a string sxpr.
+ *
+ * @param obj string sxpr
+ * @return string
+ */
+char * string_string(Sxpr obj){
+ return OBJ_STRING(obj);
+}
+
+/** Get the length of a string.
+ *
+ * @param obj string
+ * @return length
+ */
+int string_length(Sxpr obj){
+ return strlen(OBJ_STRING(obj));
+}
+
+/** Create a new string. The input string is copied,
+ * and must be null-terminated.
+ *
+ * @param s characters to put in the string
+ * @return new sxpr
+ */
+Sxpr string_new(char *s){
+ int n = (s ? strlen(s) : 0);
+ Sxpr obj;
+ obj = halloc(n+1, T_STRING);
+ if(!NOMEMP(obj)){
+ char *str = OBJ_STRING(obj);
+ strncpy(str, s, n);
+ str[n] = '\0';
+ }
+ return obj;
+}
+
+/** Free a string.
+ *
+ * @param obj to free
+ */
+void string_free(Sxpr obj){
+ hfree(obj);
+}
+
+/** Determine if a string needs escapes when printed
+ * using the given flags.
+ *
+ * @param str string to check
+ * @param flags print flags
+ * @return 1 if needs escapes, 0 otherwise
+ */
+int needs_escapes(char *str, unsigned flags){
+ char *c;
+ int val = 0;
+
+ if(str){
+ for(c=str; *c; c++){
+ if(in_alpha_class(*c)) continue;
+ if(in_decimal_digit_class(*c)) continue;
+ if(in_class(*c, "/._+:@~-")) continue;
+ val = 1;
+ break;
+ }
+ }
+ //printf("\n> val=%d str=|%s|\n", val, str);
+ return val;
+}
+
+/** Print a string to a stream, with escapes if necessary.
+ *
+ * @param io stream to print to
+ * @param str string
+ * @param flags print flags
+ * @return number of bytes written
+ */
+int _string_print(IOStream *io, char *str, unsigned flags){
+ int k = 0;
+ if((flags & PRINT_RAW) || !needs_escapes(str, flags)){
+ k += IOStream_print(io, str);
+ } else {
+ k += IOStream_print(io, "\"");
+ if(str){
+ char *s;
+ for(s = str; *s; s++){
+ if(*s < ' ' || *s >= 127 ){
+ switch(*s){
+ case '\a': k += IOStream_print(io, "\\a"); break;
+ case '\b': k += IOStream_print(io, "\\b"); break;
+ case '\f': k += IOStream_print(io, "\\f"); break;
+ case '\n': k += IOStream_print(io, "\\n"); break;
+ case '\r': k += IOStream_print(io, "\\r"); break;
+ case '\t': k += IOStream_print(io, "\\t"); break;
+ case '\v': k += IOStream_print(io, "\\v"); break;
+ default:
+ // Octal escape;
+ k += IOStream_print(io, "\\%o", *s);
+ break;
+ }
+ } else if(*s == c_double_quote ||
+ *s == c_single_quote ||
+ *s == c_escape){
+ k += IOStream_print(io, "\\%c", *s);
+ } else {
+ k+= IOStream_print(io, "%c", *s);
+ }
+ }
+ }
+ k += IOStream_print(io, "\"");
+ }
+ return k;
+}
+
+/** Print a string to a stream, with escapes if necessary.
+ *
+ * @param io stream to print to
+ * @param obj string
+ * @param flags print flags
+ * @return number of bytes written
+ */
+int string_print(IOStream *io, Sxpr obj, unsigned flags){
+ return _string_print(io, OBJ_STRING(obj), flags);
+}
+
+/** Compare an sxpr with a string for equality.
+ *
+ * @param x string to compare with
+ * @param y sxpr to compare
+ * @return 1 if equal, 0 otherwise
+ */
+int string_equal(Sxpr x, Sxpr y){
+ int ok = 0;
+ ok = eq(x,y);
+ if(ok) goto exit;
+ ok = has_type(y, T_STRING) && !strcmp(OBJ_STRING(x), OBJ_STRING(y));
+ if(ok) goto exit;
+ ok = has_type(y, T_ATOM) && !strcmp(OBJ_STRING(x), atom_name(y));
+ exit:
+ return ok;
+}
+
+/** Create a new cons cell.
+ * The cell is ONOMEM if either argument is.
+ *
+ * @param car sxpr for the car
+ * @param cdr sxpr for the cdr
+ * @return new cons
+ */
+Sxpr cons_new(Sxpr car, Sxpr cdr){
+ Sxpr obj;
+ if(NOMEMP(car) || NOMEMP(cdr)){
+ obj = ONOMEM;
+ } else {
+ obj = HALLOC(ObjCons, T_CONS);
+ if(!NOMEMP(obj)){
+ ObjCons *z = OBJ_CONS(obj);
+ z->car = car;
+ z->cdr = cdr;
+ }
+ }
+ return obj;
+}
+
+/** Push a new element onto a list.
+ *
+ * @param list list to add to
+ * @param elt element to add
+ * @return 0 if successful, error code otherwise
+ */
+int cons_push(Sxpr *list, Sxpr elt){
+ Sxpr l;
+ l = cons_new(elt, *list);
+ if(NOMEMP(l)) return -ENOMEM;
+ *list = l;
+ return 0;
+}
+
+/** Free a cons. Recursively frees the car and cdr.
+ *
+ * @param obj to free
+ */
+void cons_free(Sxpr obj){
+ Sxpr next;
+ for(; CONSP(obj); obj = next){
+ next = CDR(obj);
+ objfree(CAR(obj));
+ hfree(obj);
+ }
+ if(!NULLP(obj)){
+ objfree(obj);
+ }
+}
+
+/** Free a cons and its cdr cells, but not the car sxprs.
+ * Does nothing if called on something that is not a cons.
+ *
+ * @param obj to free
+ */
+void cons_free_cells(Sxpr obj){
+ Sxpr next;
+ for(; CONSP(obj); obj = next){
+ next = CDR(obj);
+ hfree(obj);
+ }
+}
+
+/** Print a cons.
+ * Prints the cons in list format if the cdrs are conses.
+ * uses pair (dot) format if the last cdr is not a cons (or null).
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+int cons_print(IOStream *io, Sxpr obj, unsigned flags){
+ int first = 1;
+ int k = 0;
+ k += IOStream_print(io, "(");
+ for( ; CONSP(obj) ; obj = CDR(obj)){
+ if(first){
+ first = 0;
+ } else {
+ k += IOStream_print(io, " ");
+ }
+ k += objprint(io, CAR(obj), flags);
+ }
+ if(!NULLP(obj)){
+ k += IOStream_print(io, " . ");
+ k += objprint(io, obj, flags);
+ }
+ k += IOStream_print(io, ")");
+ return (IOStream_error(io) ? -1 : k);
+}
+
+/** Compare a cons with another sxpr for equality.
+ * If y is a cons, compares the cars and cdrs recursively.
+ *
+ * @param x cons to compare
+ * @param y sxpr to compare
+ * @return 1 if equal, 0 otherwise
+ */
+int cons_equal(Sxpr x, Sxpr y){
+ return CONSP(y) &&
+ objequal(CAR(x), CAR(y)) &&
+ objequal(CDR(x), CDR(y));
+}
+
+/** Return the length of a cons list.
+ *
+ * @param obj list
+ * @return length
+ */
+int cons_length(Sxpr obj){
+ int count = 0;
+ for( ; CONSP(obj); obj = CDR(obj)){
+ count++;
+ }
+ return count;
+}
+
+/** Destructively reverse a cons list in-place.
+ * If the argument is not a cons it is returned unchanged.
+ *
+ * @param l to reverse
+ * @return reversed list
+ */
+Sxpr nrev(Sxpr l){
+ if(CONSP(l)){
+ // Iterate down the cells in the list making the cdr of
+ // each cell point to the previous cell. The last cell
+ // is the head of the reversed list.
+ Sxpr prev = ONULL;
+ Sxpr cell = l;
+ Sxpr next;
+
+ while(1){
+ next = CDR(cell);
+ CDR(cell) = prev;
+ if(!CONSP(next)) break;
+ prev = cell;
+ cell = next;
+ }
+ l = cell;
+ }
+ return l;
+}
+
+/** Print the null sxpr.
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+static int null_print(IOStream *io, Sxpr obj, unsigned flags){
+ return IOStream_print(io, "()");
+}
+
+/** Print the `unspecified' sxpr none.
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+static int none_print(IOStream *io, Sxpr obj, unsigned flags){
+ return IOStream_print(io, "<none>");
+}
+
+/** Print an integer.
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+static int int_print(IOStream *io, Sxpr obj, unsigned flags){
+ return IOStream_print(io, "%d", OBJ_INT(obj));
+}
+
+/** Print a boolean.
+ *
+ * @param io stream to print to
+ * @param obj to print
+ * @param flags print flags
+ * @return number of bytes written
+ */
+static int bool_print(IOStream *io, Sxpr obj, unsigned flags){
+ return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false));
+}
+
+int sxprp(Sxpr obj, Sxpr name){
+ return CONSP(obj) && objequal(CAR(obj), name);
+}
+
+/** Get the name of an element.
+ *
+ * @param obj element
+ * @return name
+ */
+Sxpr sxpr_name(Sxpr obj){
+ Sxpr val = ONONE;
+ if(CONSP(obj)){
+ val = CAR(obj);
+ } else if(STRINGP(obj) || ATOMP(obj)){
+ val = obj;
+ }
+ return val;
+}
+
+int sxpr_is(Sxpr obj, char *s){
+ if(ATOMP(obj)) return !strcmp(atom_name(obj), s);
+ if(STRINGP(obj)) return !strcmp(string_string(obj), s);
+ return 0;
+}
+
+int sxpr_elementp(Sxpr obj, Sxpr name){
+ return CONSP(obj) && objequal(CAR(obj), name);
+}
+
+/** Get the attributes of an sxpr.
+ *
+ * @param obj sxpr
+ * @return attributes
+ */
+Sxpr sxpr_attributes(Sxpr obj){
+ Sxpr val = ONULL;
+ if(CONSP(obj)){
+ obj = CDR(obj);
+ if(CONSP(obj)){
+ obj = CAR(obj);
+ if(sxprp(obj, intern("@"))){
+ val = CDR(obj);
+ }
+ }
+ }
+ return val;
+}
+
+Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def){
+ Sxpr val = ONONE;
+ val = assoc(sxpr_attributes(obj), key);
+ if(CONSP(val) && CONSP(CDR(val))){
+ val = CADR(def);
+ } else {
+ val = def;
+ }
+ return val;
+}
+
+/** Get the children of an sxpr.
+ *
+ * @param obj sxpr
+ * @return children
+ */
+Sxpr sxpr_children(Sxpr obj){
+ Sxpr val = ONULL;
+ if(CONSP(obj)){
+ val = CDR(obj);
+ if(CONSP(val) && sxprp(CAR(val), intern("@"))){
+ val = CDR(val);
+ }
+ }
+ return val;
+}
+
+Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def){
+ Sxpr val = ONONE;
+ Sxpr l;
+ for(l = sxpr_children(obj); CONSP(l); l = CDR(l)){
+ if(sxprp(CAR(l), name)){
+ val = CAR(l);
+ break;
+ }
+ }
+ if(NONEP(val)) val = def;
+ return val;
+}
+
+Sxpr sxpr_child0(Sxpr obj, Sxpr def){
+ Sxpr val = ONONE;
+ Sxpr l = sxpr_children(obj);
+ if(CONSP(l)){
+ val = CAR(l);
+ } else {
+ val = def;
+ }
+ return val;
+}
+
+Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def){
+ Sxpr val = ONONE;
+ val = sxpr_child(obj, name, ONONE);
+ if(NONEP(val)){
+ val = def;
+ } else {
+ val = sxpr_child0(val, def);
+ }
+ return val;
+}
+
+/** Table of interned symbols. Indexed by symbol name. */
+static HashTable *symbols = NULL;
+
+/** Hash function for entries in the symbol table.
+ *
+ * @param key to hash
+ * @return hashcode
+ */
+static Hashcode sym_hash_fn(void *key){
+ return hash_string((char*)key);
+}
+
+/** Key equality function for the symbol table.
+ *
+ * @param x to compare
+ * @param y to compare
+ * @return 1 if equal, 0 otherwise
+ */
+static int sym_equal_fn(void *x, void *y){
+ return !strcmp((char*)x, (char*)y);
+}
+
+/** Entry free function for the symbol table.
+ *
+ * @param table the entry is in
+ * @param entry being freed
+ */
+static void sym_free_fn(HashTable *table, HTEntry *entry){
+ if(entry){
+ objfree(((ObjAtom*)entry->value)->name);
+ HTEntry_free(entry);
+ }
+}
+
+/** Initialize the symbol table.
+ *
+ * @return 0 on sucess, error code otherwise
+ */
+static int init_symbols(void){
+ symbols = HashTable_new(100);
+ if(symbols){
+ symbols->key_hash_fn = sym_hash_fn;
+ symbols->key_equal_fn = sym_equal_fn;
+ symbols->entry_free_fn = sym_free_fn;
+ return 0;
+ }
+ return -1;
+}
+
+/** Cleanup the symbol table. Frees the table and all its symbols.
+ */
+void cleanup_symbols(void){
+ HashTable_free(symbols);
+ symbols = NULL;
+}
+
+/** Get the interned symbol with the given name.
+ * No new symbol is created.
+ *
+ * @return symbol or null
+ */
+Sxpr get_symbol(char *sym){
+ HTEntry *entry;
+ if(!symbols){
+ if(init_symbols()) return ONOMEM;
+ return ONULL;
+ }
+ entry = HashTable_get_entry(symbols, sym);
+ if(entry){
+ return OBJP(T_ATOM, entry->value);
+ } else {
+ return ONULL;
+ }
+}
+
+/** Get the interned symbol with the given name.
+ * Creates a new symbol if necessary.
+ *
+ * @return symbol
+ */
+Sxpr intern(char *sym){
+ Sxpr symbol = get_symbol(sym);
+ if(NULLP(symbol)){
+ if(!symbols) return ONOMEM;
+ symbol = atom_new(sym);
+ if(!NOMEMP(symbol)){
+ OBJ_ATOM(symbol)->interned = TRUE;
+ HashTable_add(symbols, atom_name(symbol), get_ptr(symbol));
+ }
+ }
+ return symbol;
+}
--- /dev/null
+/*
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _XEN_LIB_SXPR_H_
+#define _XEN_LIB_SXPR_H_
+
+#include <stdint.h>
+
+#include "hash_table.h"
+#include "iostream.h"
+#include "allocate.h"
+
+/** @file
+ * Definitions for rules and sxprs.
+ */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/** Sxpr type. */
+typedef int16_t TypeCode;
+
+/** A typed sxpr handle.*/
+typedef struct Sxpr {
+ /** Sxpr type. */
+ TypeCode type;
+ union {
+ /** Sxpr value. */
+ unsigned long ul;
+ /** Pointer. */
+ void *ptr;
+ } v;
+} Sxpr;
+
+/** Sxpr type to indicate out of memory. */
+#define T_NOMEM ((TypeCode)-1)
+/** The 'unspecified' sxpr. */
+#define T_NONE ((TypeCode)0)
+/** The empty list. */
+#define T_NULL ((TypeCode)1)
+/** Unsigned integer. */
+#define T_UINT ((TypeCode)2)
+/** A string. */
+#define T_STRING ((TypeCode)3)
+/** An atom. */
+#define T_ATOM ((TypeCode)4)
+/** A boolean. */
+#define T_BOOL ((TypeCode)5)
+
+/** A cons (pair or list). */
+#define T_CONS ((TypeCode)10)
+
+/** An error. */
+#define T_ERR ((TypeCode)40)
+
+/** An atom. */
+typedef struct ObjAtom {
+ Sxpr name;
+ Hashcode hashcode;
+ int interned;
+} ObjAtom;
+
+/** A cons (pair). */
+typedef struct ObjCons {
+ Sxpr car;
+ Sxpr cdr;
+} ObjCons;
+
+/** A vector. */
+typedef struct ObjVector {
+ int n;
+ Sxpr data[0];
+} ObjVector;
+
+/** Flags for sxpr printing. */
+enum PrintFlags {
+ PRINT_RAW = 0x001,
+ PRINT_TYPE = 0x002,
+ PRINT_PRETTY = 0x004,
+ PRINT_NUM = 0x008,
+};
+
+/** An integer sxpr.
+ *
+ * @param ty type
+ * @param val integer value
+ */
+#define OBJI(ty, val) (Sxpr){ type: (ty), v: { ul: (val) }}
+
+/** A pointer sxpr.
+ * If the pointer is non-null, returns an sxpr containing it.
+ * If the pointer is null, returns ONOMEM.
+ *
+ * @param ty type
+ * @param val pointer
+ */
+#define OBJP(ty, val) ((val) ? (Sxpr){ type: (ty), v: { ptr: (val) }} : ONOMEM)
+
+/** Make an integer sxpr containing a pointer.
+ *
+ * @param val pointer
+ */
+#define PTR(val) OBJP(T_UINT, (void*)(val))
+
+/** Make an integer sxpr.
+ * @param x value
+ */
+#define OINT(x) OBJI(T_UINT, x)
+
+/** Make an error sxpr.
+ *
+ * @param x value
+ */
+#define OERR(x) OBJI(T_ERR, x)
+
+/** Out of memory constant. */
+#define ONOMEM OBJI(T_NOMEM, 0)
+
+/** The `unspecified' constant. */
+#define ONONE OBJI(T_NONE, 0)
+
+/** Empty list constant. */
+#define ONULL OBJI(T_NULL, 0)
+
+/** False constant. */
+#define OFALSE OBJI(T_BOOL, 0)
+
+/** True constant. */
+#define OTRUE OBJI(T_BOOL, 1)
+
+/* Recognizers for the various sxpr types. */
+#define ATOMP(obj) has_type(obj, T_ATOM)
+#define BOOLP(obj) has_type(obj, T_BOOL)
+#define CONSP(obj) has_type(obj, T_CONS)
+#define ERRP(obj) has_type(obj, T_ERR)
+#define INTP(obj) has_type(obj, T_UINT)
+#define NOMEMP(obj) has_type(obj, T_NOMEM)
+#define NONEP(obj) has_type(obj, T_NONE)
+#define NULLP(obj) has_type(obj, T_NULL)
+#define STRINGP(obj) has_type(obj, T_STRING)
+
+#define TRUEP(obj) get_ul(obj)
+
+/** Convert an sxpr to an unsigned integer. */
+#define OBJ_UINT(x) get_ul(x)
+/** Convert an sxpr to an integer. */
+#define OBJ_INT(x) (int)get_ul(x)
+
+/* Conversions of sxprs to their values.
+ * No checking is done.
+ */
+#define OBJ_STRING(x) ((char*)get_ptr(x))
+#define OBJ_CONS(x) ((ObjCons*)get_ptr(x))
+#define OBJ_ATOM(x) ((ObjAtom*)get_ptr(x))
+#define OBJ_SET(x) ((ObjSet*)get_ptr(x))
+#define CAR(x) (OBJ_CONS(x)->car)
+#define CDR(x) (OBJ_CONS(x)->cdr)
+
+#define CAAR(x) (CAR(CAR(x)))
+#define CADR(x) (CAR(CDR(x)))
+#define CDAR(x) (CDR(CAR(x)))
+#define CDDR(x) (CDR(CDR(x)))
+
+/** Get the integer value from an sxpr.
+ *
+ * @param obj sxpr
+ * @return value
+ */
+static inline unsigned long get_ul(Sxpr obj){
+ return obj.v.ul;
+}
+
+/** Get the pointer value from an sxpr.
+ *
+ * @param obj sxpr
+ * @return value
+ */
+static inline void * get_ptr(Sxpr obj){
+ return obj.v.ptr;
+}
+
+/** Create an sxpr containing a pointer.
+ *
+ * @param type typecode
+ * @param val pointer
+ * @return sxpr
+ */
+static inline Sxpr obj_ptr(TypeCode type, void *val){
+ return (Sxpr){ type: type, v: { ptr: val } };
+}
+
+/** Create an sxpr containing an integer.
+ *
+ * @param type typecode
+ * @param val integer
+ * @return sxpr
+ */
+static inline Sxpr obj_ul(TypeCode type, unsigned long val){
+ return (Sxpr){ type: type, v: { ul: val } };
+}
+
+/** Get the type of an sxpr.
+ *
+ * @param obj sxpr
+ * @return type
+ */
+static inline TypeCode get_type(Sxpr obj){
+ return obj.type;
+}
+
+/** Check the type of an sxpr.
+ *
+ * @param obj sxpr
+ * @param type to check
+ * @return 1 if has the type, 0 otherwise
+ */
+static inline int has_type(Sxpr obj, TypeCode type){
+ return get_type(obj) == type;
+}
+
+/** Compare sxprs for literal equality of type and value.
+ *
+ * @param x sxpr to compare
+ * @param y sxpr to compare
+ * @return 1 if equal, 0 otherwise
+ */
+static inline int eq(Sxpr x, Sxpr y){
+ return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y)));
+}
+
+/** Checked version of CAR
+ *
+ * @param x sxpr
+ * @return CAR if a cons, x otherwise
+ */
+static inline Sxpr car(Sxpr x){
+ return (CONSP(x) ? CAR(x) : x);
+}
+
+/** Checked version of CDR.
+ *
+ * @param x sxpr
+ * @return CDR if a cons, null otherwise
+ */
+static inline Sxpr cdr(Sxpr x){
+ return (CONSP(x) ? CDR(x) : ONULL);
+}
+
+/** Allocate some memory and return an sxpr containing it.
+ * Returns ONOMEM if allocation failed.
+ *
+ * @param n number of bytes to allocate
+ * @param ty typecode
+ * @return sxpr
+ */
+static inline Sxpr halloc(size_t n, TypeCode ty){
+ return OBJP(ty, allocate(n));
+}
+
+/** Allocate an sxpr containing a pointer to the given type.
+ *
+ * @param ty type (uses sizeof to determine how many bytes to allocate)
+ * @param code typecode
+ * @return sxpr, ONOMEM if allocation failed
+ */
+#define HALLOC(ty, code) halloc(sizeof(ty), code)
+
+typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags);
+typedef int ObjEqualFn(Sxpr obj, Sxpr other);
+typedef void ObjFreeFn(Sxpr obj);
+
+/** An sxpr type definition. */
+typedef struct SxprType {
+ TypeCode type;
+ char *name;
+ int pointer;
+ ObjPrintFn *print;
+ ObjEqualFn *equal;
+ ObjFreeFn *free;
+} SxprType;
+
+
+extern SxprType *get_sxpr_type(int ty);
+
+/** Free the pointer in an sxpr.
+ *
+ * @param x sxpr containing a pointer
+ */
+static inline void hfree(Sxpr x){
+ deallocate(get_ptr(x));
+}
+
+extern int objprint(IOStream *io, Sxpr x, unsigned flags);
+extern int objequal(Sxpr x, Sxpr y);
+extern void objfree(Sxpr x);
+
+extern void cons_free_cells(Sxpr obj);
+extern Sxpr intern(char *s);
+
+extern Sxpr assoc(Sxpr k, Sxpr l);
+extern Sxpr assocq(Sxpr k, Sxpr l);
+extern Sxpr acons(Sxpr k, Sxpr v, Sxpr l);
+extern Sxpr nrev(Sxpr l);
+extern Sxpr cons_member(Sxpr l, Sxpr x);
+extern Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
+extern int cons_subset(Sxpr s, Sxpr t);
+extern int cons_set_equal(Sxpr s, Sxpr t);
+
+#ifdef USE_GC
+extern Sxpr cons_remove(Sxpr l, Sxpr x);
+extern Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
+#endif
+
+extern Sxpr atom_new(char *name);
+extern char * atom_name(Sxpr obj);
+
+extern Sxpr string_new(char *s);
+extern char * string_string(Sxpr obj);
+extern int string_length(Sxpr obj);
+
+extern Sxpr cons_new(Sxpr car, Sxpr cdr);
+extern int cons_push(Sxpr *list, Sxpr elt);
+extern int cons_length(Sxpr obj);
+
+Sxpr sxpr_name(Sxpr obj);
+int sxpr_is(Sxpr obj, char *s);
+int sxpr_elementp(Sxpr obj, Sxpr name);
+Sxpr sxpr_attributes(Sxpr obj);
+Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def);
+Sxpr sxpr_children(Sxpr obj);
+Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def);
+Sxpr sxpr_child0(Sxpr obj, Sxpr def);
+Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def);
+
+/** Create a new atom.
+ *
+ * @param s atom name
+ * @return new atom
+ */
+static inline Sxpr mkatom(char *s){
+ return atom_new(s);
+}
+
+/** Create a new string sxpr.
+ *
+ * @param s string bytes (copied)
+ * @return new string
+ */
+static inline Sxpr mkstring(char *s){
+ return string_new(s);
+}
+
+/** Create an integer sxpr.
+ *
+ * @param i value
+ * @return sxpr
+ */
+static inline Sxpr mkint(int i){
+ return OBJI(T_UINT, i);
+}
+
+/** Create a boolean sxpr.
+ *
+ * @param b value
+ * @return sxpr
+ */
+static inline Sxpr mkbool(int b){
+ return OBJI(T_BOOL, (b ? 1 : 0));
+}
+
+/* Constants used in parsing and printing. */
+#define k_list_open "("
+#define c_list_open '('
+#define k_list_close ")"
+#define c_list_close ')'
+#define k_true "true"
+#define k_false "false"
+
+#define c_var '$'
+#define c_escape '\\'
+#define c_single_quote '\''
+#define c_double_quote '"'
+#define c_string_open c_double_quote
+#define c_string_close c_double_quote
+#define c_data_open '['
+#define c_data_close ']'
+#define c_binary '*'
+#define c_eval '!'
+#define c_concat_open '{'
+#define c_concat_close '}'
+
+#endif /* ! _XEN_LIB_SXPR_H_ */
--- /dev/null
+
+#ifdef __KERNEL__
+# include <linux/config.h>
+# include <linux/module.h>
+# include <linux/kernel.h>
+# include <linux/string.h>
+# include <linux/errno.h>
+#else
+# include <stdlib.h>
+# include <errno.h>
+#endif
+
+#include "iostream.h"
+#include "lexis.h"
+#include "sxpr_parser.h"
+#include "sys_string.h"
+
+/** @file
+ * Sxpr parsing.
+ *
+ * So that the parser does not leak memory, all sxprs constructed by
+ * the parser must be freed on error. On successful parse the sxpr
+ * returned becomes the responsibility of the caller.
+ *
+ * @author Mike Wray <mike.wray@hpl.hp.com>
+ */
+
+#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
+#define printf(fmt, args...) IOStream_print(iostdout, fmt, ##args)
+
+static void reset(Parser *z);
+static int inputchar(Parser *p, char c);
+static int savechar(Parser *p, char c);
+extern void parse_error(Parser *in);
+extern void parse_error_id(Parser *in, ParseErrorId id);
+
+static int begin_start(Parser *p, char c);
+static int state_start(Parser *p, char c);
+static int end_start(Parser *p);
+
+static int begin_comment(Parser *p, char c);
+static int state_comment(Parser *p, char c);
+static int end_comment(Parser *p);
+
+static int begin_string(Parser *p, char c);
+static int state_string(Parser *p, char c);
+static int end_string(Parser *p);
+static int state_escape(Parser *p, char c);
+static int state_octal(Parser *p, char c);
+static int state_hex(Parser *p, char c);
+
+static int begin_atom(Parser *p, char c);
+static int state_atom(Parser *p, char c);
+static int end_atom(Parser *p);
+
+static int state_list(Parser *p, char c);
+static int begin_list(Parser *p, char c);
+static int end_list(Parser *p);
+
+/** Print a parse error.
+ *
+ * @param in parser
+ * @param msg format followed by printf arguments
+ */
+void eprintf(Parser *in, char *msg, ...){
+ va_list args;
+ if(in->error_out){
+ va_start(args, msg);
+ IOStream_vprint(in->error_out, msg, args);
+ va_end(args);
+ }
+}
+
+/** Print a parse warning.
+ *
+ * @param in parser
+ * @param msg format followed by printf arguments
+ */
+void wprintf(Parser *in, char *msg, ...){
+ va_list args;
+ if(in->error_out){
+ va_start(args, msg);
+ IOStream_vprint(in->error_out, msg, args);
+ va_end(args);
+ }
+}
+
+/*============================================================================*/
+
+/** Record defining the message for a parse error. */
+typedef struct {
+ ParseErrorId id;
+ char *message;
+} ParseError;
+
+/** Format for printing parse error messages. */
+#define PARSE_ERR_FMT "parse error> line %3d, column %2d: %s"
+
+/** Message catalog for the parse error codes. */
+static ParseError catalog[] = {
+ { PARSE_ERR_UNSPECIFIED, "unspecified error" },
+ { PARSE_ERR_NOMEM, "out of memory" },
+ { PARSE_ERR_UNEXPECTED_EOF, "unexpected end of input" },
+ { PARSE_ERR_TOKEN_TOO_LONG, "token too long" },
+ { PARSE_ERR_INVALID_SYNTAX, "syntax error" },
+ { PARSE_ERR_INVALID_ESCAPE, "invalid escape" },
+ { 0, NULL }
+};
+
+/** Number of entries in the message catalog. */
+const static int catalog_n = sizeof(catalog)/sizeof(ParseError);
+
+void ParserState_free(ParserState *z){
+ if(!z) return;
+ objfree(z->val);
+ deallocate(z);
+}
+
+int ParserState_new(ParserStateFn *fn, ParserState *parent, ParserState **val){
+ int err = 0;
+ ParserState *z;
+ z = ALLOCATE(ParserState);
+ if(z){
+ z->fn = fn;
+ z->parent = parent;
+ z->val = ONULL;
+ } else {
+ err = -ENOMEM;
+ }
+ if(!err) *val = z;
+ return err;
+}
+
+/** Free a parser.
+ * No-op if the parser is null.
+ *
+ * @param z parser
+ */
+void Parser_free(Parser *z){
+ if(!z) return;
+ objfree(z->val);
+ z->val = ONONE;
+ deallocate(z);
+}
+
+/** Create a new parser. The error stream defaults to null.
+ */
+Parser * Parser_new(void){
+ Parser *z = ALLOCATE(Parser);
+ int err = -ENOMEM;
+
+ if(!z) goto exit;
+ err = 0;
+ reset(z);
+ exit:
+ if(err){
+ Parser_free(z);
+ z = NULL;
+ }
+ return z;
+}
+
+/** Get the next character.
+ * Records the character read in the parser,
+ * and sets the line and character counts.
+ *
+ * @param p parser
+ * @return error flag: 0 on success, non-zero on error
+ */
+static int inputchar(Parser *p, char c){
+ int err = 0;
+ if(c=='\n'){
+ p->line_no++;
+ p->char_no = 0;
+ } else {
+ p->char_no++;
+ }
+ return err;
+}
+
+static int savechar(Parser *p, char c){
+ int err = 0;
+ if(p->buf_i >= p->buf_n){
+ err = -ENOMEM;
+ goto exit;
+ }
+ p->buf[p->buf_i] = c;
+ p->buf_i++;
+ exit:
+ return err;
+}
+
+int Parser_input_char(Parser *p, char c){
+ int err = 0;
+ if(at_eof(p)){
+ //skip;
+ } else {
+ inputchar(p, c);
+ }
+ if(!p->state){
+ err = begin_start(p, c);
+ if(err) goto exit;
+ }
+ err = p->state->fn(p, c);
+ exit:
+ return err;
+}
+
+int Parser_input_eof(Parser *p){
+ int err = 0;
+ p->eof = 1;
+ err = Parser_input_char(p, IOSTREAM_EOF);
+ return err;
+}
+
+int Parser_input(Parser *p, char *buf, int buf_n){
+ int err = 0;
+ int i = 0;
+ if(buf_n <= 0){
+ err = Parser_input_eof(p);
+ goto exit;
+ }
+ for(i = 0; i<buf_n; i++){
+ err = Parser_input_char(p, buf[i]);
+ if(err) goto exit;
+ }
+ exit:
+ err = (err < 0 ? err : buf_n);
+ return err;
+}
+
+int Parser_push(Parser *p, ParserStateFn *fn){
+ int err = 0;
+ err = ParserState_new(fn, p->state, &p->state);
+ return err;
+}
+
+int Parser_pop(Parser *p){
+ int err = 0;
+ ParserState *s = p->state;
+ p->state = s->parent;
+ ParserState_free(s);
+ return err;
+}
+
+int Parser_return(Parser *p){
+ int err = 0;
+ Sxpr val = ONONE;
+ if(!p->state){
+ err = -EINVAL;
+ goto exit;
+ }
+ val = p->state->val;
+ p->state->val = ONONE;
+ err = Parser_pop(p);
+ if(err) goto exit;
+ if(p->state){
+ err = cons_push(&p->state->val, val);
+ } else {
+ val = nrev(val);
+ p->val = val;
+ }
+ exit:
+ if(err){
+ objfree(val);
+ }
+ return err;
+}
+
+/** Determine if a character is a separator.
+ *
+ * @param p parser
+ * @param c character to test
+ * @return 1 if a separator, 0 otherwise
+ */
+static int is_separator(Parser *p, char c){
+ return in_sep_class(c);
+}
+
+/** Return the current token.
+ * The return value points at the internal buffer, so
+ * it must not be modified (or freed). Use copy_token() if you need a copy.
+ *
+ * @param p parser
+ * @return token
+ */
+char *peek_token(Parser *p){
+ return p->buf;
+}
+
+/** Return a copy of the current token.
+ * The returned value should be freed when finished with.
+ *
+ * @param p parser
+ * @return copy of token
+ */
+char *copy_token(Parser *p){
+ return strdup(peek_token(p));
+}
+
+static int do_intern(Parser *p){
+ int err = 0;
+ Sxpr obj = intern(peek_token(p));
+ if(NOMEMP(obj)){
+ err = -ENOMEM;
+ } else {
+ p->state->val = obj;
+ }
+ return err;
+}
+
+static int do_string(Parser *p){
+ int err = 0;
+ Sxpr obj;
+ obj = string_new(peek_token(p));
+ if(NOMEMP(obj)){
+ err = -ENOMEM;
+ } else {
+ p->state->val = obj;
+ }
+ return err;
+}
+
+void newtoken(Parser *p){
+ memset(p->buf, 0, p->buf_n);
+ p->buf_i = 0;
+ p->tok_begin_line = p->line_no;
+ p->tok_begin_char = p->char_no;
+}
+
+int get_escape(char c, char *d){
+ int err = 0;
+ switch(c){
+ case 'a': *d = '\a'; break;
+ case 'b': *d = '\b'; break;
+ case 'f': *d = '\f'; break;
+ case 'n': *d = '\n'; break;
+ case 'r': *d = '\r'; break;
+ case 't': *d = '\t'; break;
+ case 'v': *d = '\v'; break;
+ case c_escape: *d = c_escape; break;
+ case c_single_quote: *d = c_single_quote; break;
+ case c_double_quote: *d = c_double_quote; break;
+ default:
+ err = -EINVAL;
+ }
+ return err;
+}
+
+
+int begin_start(Parser *p, char c){
+ return Parser_push(p, state_start);
+}
+
+int state_start(Parser *p, char c){
+ int err = 0;
+ if(at_eof(p)){
+ err = end_start(p);
+ } else if(in_space_class(c)){
+ //skip
+ } else if(in_comment_class(c)){
+ begin_comment(p, c);
+ } else if(c == c_list_open){
+ begin_list(p, c);
+ } else if(c == c_list_close){
+ parse_error(p);
+ err = -EINVAL;
+ } else if(in_string_quote_class(c)){
+ begin_string(p, c);
+ } else if(in_printable_class(c)){
+ begin_atom(p, c);
+ } else if(c == 0x04){
+ //ctrl-D, EOT: end-of-text.
+ Parser_input_eof(p);
+ } else {
+ parse_error(p);
+ err = -EINVAL;
+ }
+ return err;
+}
+
+int end_start(Parser *p){
+ int err = 0;
+ err = Parser_return(p);
+ return err;
+}
+
+int begin_comment(Parser *p, char c){
+ int err = 0;
+ err = Parser_push(p, state_comment);
+ if(err) goto exit;
+ err = inputchar(p, c);
+ exit:
+ return err;
+}
+
+int state_comment(Parser *p, char c){
+ int err = 0;
+ if(c == '\n' || at_eof(p)){
+ err = end_comment(p);
+ } else {
+ err = inputchar(p, c);
+ }
+ return err;
+}
+
+int end_comment(Parser *p){
+ return Parser_pop(p);
+}
+
+int begin_string(Parser *p, char c){
+ int err = 0;
+ err = Parser_push(p, state_string);
+ if(err) goto exit;
+ newtoken(p);
+ p->state->delim = c;
+ exit:
+ return err;
+}
+
+int state_string(Parser *p, char c){
+ int err = 0;
+ if(at_eof(p)){
+ parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+ err = -EINVAL;
+ } else if(c == p->state->delim){
+ err = end_string(p);
+ } else if(c == '\\'){
+ err = Parser_push(p, state_escape);
+ } else {
+ err = savechar(p, c);
+ }
+ return err;
+}
+
+int end_string(Parser *p){
+ int err = 0;
+ err = do_string(p);
+ if(err) goto exit;
+ err = Parser_return(p);
+ exit:
+ return err;
+}
+
+int state_escape(Parser *p, char c){
+ int err = 0;
+ char d;
+ if(at_eof(p)){
+ parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+ err = -EINVAL;
+ goto exit;
+ }
+ if(get_escape(c, &d) == 0){
+ err = savechar(p, d);
+ if(err) goto exit;
+ err = Parser_pop(p);
+ } else if(c == 'x'){
+ p->state->fn = state_hex;
+ p->state->ival = 0;
+ p->state->count = 0;
+ } else {
+ p->state->fn = state_octal;
+ p->state->ival = 0;
+ p->state->count = 0;
+ err = Parser_input_char(p, c);
+ }
+ exit:
+ return err;
+}
+
+int octaldone(Parser *p){
+ int err = 0;
+ char d = (char)(p->state->ival & 0xff);
+ err = Parser_pop(p);
+ if(err) goto exit;
+ err = Parser_input_char(p, d);
+ exit:
+ return err;
+}
+
+int octaldigit(Parser *p, char c){
+ int err = 0;
+ p->state->ival *= 8;
+ p->state->ival += c - '0';
+ p->state->count++;
+ if(err) goto exit;
+ if(p->state->ival < 0 || p->state->ival > 0xff){
+ parse_error(p);
+ err = -EINVAL;
+ goto exit;
+ }
+ if(p->state->count == 3){
+ err = octaldone(p);
+ }
+ exit:
+ return err;
+}
+
+int state_octal(Parser *p, char c){
+ int err = 0;
+ if(at_eof(p)){
+ parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+ err = -EINVAL;
+ goto exit;
+ } else if('0' <= c && c <= '7'){
+ err = octaldigit(p, c);
+ } else {
+ err = octaldone(p);
+ if(err) goto exit;
+ Parser_input_char(p, c);
+ }
+ exit:
+ return err;
+}
+
+int hexdone(Parser *p){
+ int err = 0;
+ char d = (char)(p->state->ival & 0xff);
+ err = Parser_pop(p);
+ if(err) goto exit;
+ err = Parser_input_char(p, d);
+ exit:
+ return err;
+}
+
+int hexdigit(Parser *p, char c, char d){
+ int err = 0;
+ p->state->ival *= 16;
+ p->state->ival += c - d;
+ p->state->count++;
+ if(err) goto exit;
+ if(p->state->ival < 0 || p->state->ival > 0xff){
+ parse_error(p);
+ err = -EINVAL;
+ goto exit;
+ }
+ if(p->state->count == 2){
+ err = hexdone(p);
+ }
+ exit:
+ return err;
+}
+
+int state_hex(Parser *p, char c){
+ int err = 0;
+ if(at_eof(p)){
+ parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+ err = -EINVAL;
+ goto exit;
+ } else if('0' <= c && c <= '9'){
+ err = hexdigit(p, c, '0');
+ } else if('A' <= c && c <= 'F'){
+ err = hexdigit(p, c, 'A');
+ } else if('a' <= c && c <= 'f'){
+ err = hexdigit(p, c, 'a');
+ } else if(p->state->count){
+ err =hexdone(p);
+ if(err) goto exit;
+ Parser_input_char(p, c);
+ }
+ exit:
+ return err;
+}
+
+int begin_atom(Parser *p, char c){
+ int err = 0;
+ err = Parser_push(p, state_atom);
+ if(err) goto exit;
+ newtoken(p);
+ err = savechar(p, c);
+ exit:
+ return err;
+}
+
+int state_atom(Parser *p, char c){
+ int err = 0;
+ if(at_eof(p)){
+ err = end_atom(p);
+ } else if(is_separator(p, c) ||
+ in_space_class(c) ||
+ in_comment_class(c)){
+ err = end_atom(p);
+ if(err) goto exit;
+ err = Parser_input_char(p, c);
+ } else {
+ err = savechar(p, c);
+ }
+ exit:
+ return err;
+}
+
+int end_atom(Parser *p){
+ int err = 0;
+ err = do_intern(p);
+ if(err) goto exit;
+ err = Parser_return(p);
+ exit:
+ return err;
+}
+
+int state_list(Parser *p, char c){
+ int err = 0;
+ if(at_eof(p)){
+ parse_error_id(p, PARSE_ERR_UNEXPECTED_EOF);
+ err = -EINVAL;
+ } else if(c == c_list_close){
+ p->state->val = nrev(p->state->val);
+ err = end_list(p);
+ } else {
+ err = state_start(p, c);
+ }
+ return err;
+
+}
+
+int begin_list(Parser *p, char c){
+ return Parser_push(p, state_list);
+}
+
+int end_list(Parser *p){
+ return Parser_return(p);
+}
+
+/** Reset the fields of a parser to initial values.
+ *
+ * @param z parser
+ */
+static void reset(Parser *z){
+ IOStream *error_out = z->error_out;
+ int flags = z->flags;
+ zero(z, sizeof(Parser));
+ z->buf_n = sizeof(z->buf) - 1;
+ z->buf_i = 0;
+ z->line_no = 1;
+ z->char_no = 0;
+ z->error_out = error_out;
+ z->flags = flags;
+}
+
+/** Set the parser error stream.
+ * Parse errors are reported on the the error stream if it is non-null.
+ *
+ * @param z parser
+ * @param error_out error stream
+ */
+void set_error_stream(Parser *z, IOStream *error_out){
+ if(z){
+ z->error_out = error_out;
+ }
+}
+
+/** Get the parser error message for an error code.
+ *
+ * @param id error code
+ * @return error message (empty string if the code is unknown)
+ */
+static char *get_message(ParseErrorId id){
+ int i;
+ for(i=0; i<catalog_n; i++){
+ if(id == catalog[i].id){
+ return catalog[i].message;
+ }
+ }
+ return "";
+}
+
+/** Get the line number.
+ *
+ * @param in parser
+ */
+int get_line(Parser *in){
+ return in->line_no;
+}
+
+/** Get the column number.
+ *
+ * @param in parser
+ */
+int get_column(Parser *in){
+ return in->char_no;
+}
+
+/** Get the line number the current token started on.
+ *
+ * @param in parser
+ */
+int get_tok_line(Parser *in){
+ return in->tok_begin_line;
+}
+
+/** Get the column number the current token started on.
+ *
+ * @param in parser
+ */
+int get_tok_column(Parser *in){
+ return in->tok_begin_char;
+}
+
+/** Report a parse error.
+ * Does nothing if the error stream is null or there is no error.
+ *
+ * @param in parser
+ */
+static void report_error(Parser *in){
+ if(in->error_out && in->err){
+ char *msg = get_message(in->err);
+ char *tok = peek_token(in);
+ IOStream_print(in->error_out, PARSE_ERR_FMT,
+ get_tok_line(in), get_tok_column(in), msg);
+ if(tok && tok[0]){
+ IOStream_print(in->error_out, " '%s'", tok);
+ }
+ IOStream_print(in->error_out, "\n");
+ }
+}
+
+/** Get the error message for the current parse error code.
+ * Does nothing if there is no error.
+ *
+ * @param in parser
+ * @param buf where to place the message
+ * @param n maximum number of characters to place in buf
+ * @return current error code (zero for no error)
+ */
+int parse_error_message(Parser *in, char *buf, int n){
+ if(in->err){
+ char *msg = get_message(in->err);
+ snprintf(buf, n, PARSE_ERR_FMT, get_tok_line(in), get_tok_column(in), msg);
+ }
+ return in->err;
+}
+
+/** Flag an unspecified parse error. All subsequent reads will fail.
+ *
+ * @param in parser
+ */
+void parse_error(Parser *in){
+ parse_error_id(in, PARSE_ERR_INVALID_SYNTAX);
+}
+
+/** Flag a parse error. All subsequent reads will fail.
+ * Does not change the parser error code if it is already set.
+ *
+ * @param in parser
+ * @param id error code
+ */
+void parse_error_id(Parser *in, ParseErrorId id){
+ if(!in->err){
+ in->err = id;
+ report_error(in);
+ }
+}
+
+/** Test if the parser's error flag is set.
+ *
+ * @param in parser
+ * @return 1 if set, 0 otherwise
+ */
+int has_error(Parser *in){
+ return (in->err > 0);
+}
+
+/** Test if the parser is at end of input.
+ *
+ * @param in parser
+ * @return 1 if at EOF, 0 otherwise
+ */
+int at_eof(Parser *p){
+ return p->eof;
+}
+
+#ifdef SXPR_PARSER_MAIN
+/* Stuff for standalone testing. */
+
+#include "file_stream.h"
+#include "string_stream.h"
+
+int stringof(Sxpr exp, char **s){
+ int err = 0;
+ if(ATOMP(exp)){
+ *s = atom_name(exp);
+ } else if(STRINGP(exp)){
+ *s = string_string(exp);
+ } else {
+ err = -EINVAL;
+ *s = NULL;
+ }
+ return err;
+}
+
+int child_string(Sxpr exp, Sxpr key, char **s){
+ int err = 0;
+ Sxpr val = sxpr_child_value(exp, key, ONONE);
+ err = stringof(val, s);
+ return err;
+}
+
+int intof(Sxpr exp, int *v){
+ int err = 0;
+ char *s;
+ unsigned long l;
+ if(INTP(exp)){
+ *v = OBJ_INT(exp);
+ } else {
+ err = stringof(exp, &s);
+ if(err) goto exit;
+ err = convert_atoul(s, &l);
+ *v = (int)l;
+ }
+ exit:
+ return err;
+}
+
+int child_int(Sxpr exp, Sxpr key, int *v){
+ int err = 0;
+ Sxpr val = sxpr_child_value(exp, key, ONONE);
+ err = intof(val, v);
+ return err;
+}
+
+int eval_vnet(Sxpr exp){
+ int err = 0;
+ Sxpr oid = intern("id");
+ int id;
+ err = child_int(exp, oid, &id);
+ if(err) goto exit;
+ dprintf("> vnet id=%d\n", id);
+ exit:
+ dprintf("< err=%d\n", err);
+ return err;
+}
+
+int eval_connect(Sxpr exp){
+ int err = 0;
+ Sxpr ovif = intern("vif");
+ Sxpr ovnet = intern("vnet");
+ char *vif;
+ int vnet;
+
+ err = child_string(exp, ovif, &vif);
+ if(err) goto exit;
+ err = child_int(exp, ovnet, &vnet);
+ if(err) goto exit;
+ dprintf("> connect vif=%s vnet=%d\n", vif, vnet);
+ exit:
+ dprintf("< err=%d\n", err);
+ return err;
+}
+
+int eval(Sxpr exp){
+ int err = 0;
+ Sxpr oconnect = intern("connect");
+ Sxpr ovnet = intern("vnet");
+
+ if(sxpr_elementp(exp, ovnet)){
+ err = eval_vnet(exp);
+ } else if(sxpr_elementp(exp, oconnect)){
+ err = eval_connect(exp);
+ } else {
+ err = -EINVAL;
+ }
+ return err;
+}
+
+/** Main program for testing.
+ * Parses input and prints it.
+ *
+ * @param argc number of arguments
+ * @param argv arguments
+ * @return error code
+ */
+int main(int argc, char *argv[]){
+ Parser *pin;
+ int err = 0;
+ char buf[1024];
+ int k;
+ Sxpr obj, l, x;
+
+ pin = Parser_new();
+ set_error_stream(pin, iostdout);
+ dprintf("> parse...\n");
+ while(1){
+ k = fread(buf, 1, 1024, stdin);
+ err = Parser_input(pin, buf, k);
+ dprintf("> Parser_input=%d\n", err);
+ if(k <= 0) break;
+ }
+ obj = pin->val;
+ for(l = obj ; CONSP(l); l = CDR(l)){
+ x = CAR(l);
+ objprint(iostdout, x, 0); printf("\n");
+ eval(x);
+ }
+ dprintf("> err=%d\n", err);
+ return 0;
+}
+#endif
--- /dev/null
+/*
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XEN_LIB_SXPR_PARSER_H_
+#define _XEN_LIB_SXPR_PARSER_H_
+
+#include "sxpr.h"
+#include "iostream.h"
+
+/** @file
+ * Sxpr parsing definitions.
+ */
+
+/** Size of a parser input buffer.
+ * Tokens read must fit into this size (including trailing null).
+ */
+#define PARSER_BUF_SIZE 1024
+
+struct Parser;
+typedef int ParserStateFn(struct Parser *, char c);
+
+typedef struct ParserState {
+ struct ParserState *parent;
+ Sxpr val;
+ int ival;
+ int count;
+ char delim;
+ ParserStateFn *fn;
+} ParserState;
+
+/** Structure representing an input source for the parser.
+ * Can read from any IOStream implementation.
+ */
+typedef struct Parser {
+ Sxpr val;
+ /** Error reporting stream (null for no reports). */
+ IOStream *error_out;
+ int eof;
+ /** Error flag. Non-zero if there has been a read error. */
+ int err;
+ /** Line number on input (from 1). */
+ int line_no;
+ /** Column number of input (reset on new line). */
+ int char_no;
+ /** Lookahead character. */
+ char c;
+ /** Buffer for reading tokens. */
+ char buf[PARSER_BUF_SIZE];
+ /** Size of token buffer. */
+ int buf_n;
+ int buf_i;
+ /** Line the last token started on. */
+ int tok_begin_line;
+ /** Character number the last token started on. */
+ int tok_begin_char;
+ /** Parsing flags. */
+ int flags;
+ ParserState *state;
+} Parser;
+
+/** Parser error codes. */
+typedef enum {
+ PARSE_ERR_NONE=0,
+ PARSE_ERR_UNSPECIFIED,
+ PARSE_ERR_NOMEM,
+ PARSE_ERR_UNEXPECTED_EOF,
+ PARSE_ERR_TOKEN_TOO_LONG,
+ PARSE_ERR_INVALID_SYNTAX,
+ PARSE_ERR_INVALID_ESCAPE,
+} ParseErrorId;
+
+
+/** Parser flags. */
+//enum {
+//};
+
+/** Raise some parser flags.
+ *
+ * @param in parser
+ * @param flags flags mask
+ */
+inline static void parser_flags_raise(Parser *in, int flags){
+ in->flags |= flags;
+}
+
+/** Lower some parser flags.
+ *
+ * @param in parser
+ * @param flags flags mask
+ */
+inline static void parser_flags_lower(Parser *in, int flags){
+ in->flags &= ~flags;
+}
+
+/** Clear all parser flags.
+ *
+ * @param in parser
+ */
+inline static void parser_flags_clear(Parser *in){
+ in->flags = 0;
+}
+
+extern void Parser_free(Parser *z);
+extern Parser * Parser_new(void);
+extern int Parser_input(Parser *p, char *buf, int buf_n);
+extern int Parser_input_eof(Parser *p);
+
+extern int parse_error_message(Parser *in, char *buf, int n);
+extern int has_error(Parser *in);
+extern int at_eof(Parser *in);
+
+#endif /* ! _XEN_LIB_SXPR_PARSER_H_ */
--- /dev/null
+#ifndef _XENO_SYS_CTYPE_H_
+#define _XENO_SYS_CTYPE_H_
+/** @file
+ ** Replacement for ctype include that can be used
+ * from user or kernel code.
+ */
+#ifdef __KERNEL__
+# include <linux/ctype.h>
+#else
+# include <ctype.h>
+#endif
+#endif /* ! _XENO_SYS_CTYPE_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This library is
+ * distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "sys_net.h"
+#include "sys_string.h"
+
+/** @file
+ * All network data are kept in network order and only converted to
+ * host order for display. Network data includes IP addresses, port numbers and
+ * network masks.
+ */
+
+/** Maximum value for a port. */
+#define PORT_MAX 0xffff
+
+/** Convert a number of bits to a network mask
+ * for IP addresses. The number of bits must
+ * be in the range 1-31.
+ *
+ * @param n number of bits to set in the mask
+ * @return value with n high bits set (in network order)
+ */
+unsigned long bits_to_mask(int n){
+ unsigned long mask = (n ? (1 << 31) : 0);
+ int i;
+ for(i=1; i<n; i++){
+ mask |= (mask >> 1);
+ }
+ return htonl(mask);
+}
+
+/** Convert a network mask to a number of bits.
+ *
+ * @param mask network mask in network order
+ * @return number of bits in mask
+ */
+int mask_to_bits(unsigned long mask){
+ // Start with n set to the number of bits in the mask. Then reduce n by
+ // the number of low zero bits in the mask.
+ int n = 32;
+ for(mask = ntohl(mask);
+ (mask & 1)==0 && n>0;
+ mask >>= 1){
+ n--;
+ }
+ return n;
+}
+
+/** Get the index of the first occurrence of a character in a string.
+ * Stops at end of string or after n characters.
+ *
+ * @param s input string
+ * @param n maximum number of charactes to search
+ * @param c character to look for
+ * @return index of first occurrence, -1 if not found
+ */
+inline static int indexof(const char *s, int n, char c){
+ int i;
+ for(i=0; i<n && *s; i++, s++){
+ if(*s == c) return i;
+ }
+ return -1;
+}
+
+/** Convert an IPv4 address in dot notation into an unsigned long (in network order).
+ *
+ * @param s input string
+ * @param address where to put the address
+ * @return 0 on success, -1 on error
+ */
+int get_inet_addr(const char *s, unsigned long *address){
+ // Number of bits in a byte.
+ const int BYTE_BITS = 8;
+ // Number of bytes in a word.
+ const int WORD_BYTES = 4;
+ // Max value for a component of an address.
+ const int ADDR_MAX = 255;
+ // Separator for components of an address.
+ const char dot = '.';
+
+ int n;
+ unsigned long addr = 0;
+ unsigned long v;
+ int i;
+ int err = -1;
+ // Bit shift for the current byte.
+ int shift = BYTE_BITS * (WORD_BYTES - 1);
+ char buf[64];
+
+ n = strlen(s);
+ if(n >= sizeof(buf)){
+ goto exit;
+ }
+ for(i=0; i < WORD_BYTES; i++){
+ int idx = indexof(s, n, dot);
+ idx = (idx < 0 ? strlen(s) : idx);
+ strncpy(buf, s, idx); buf[idx]='\0';
+ if(convert_atoul(buf, &v)){
+ goto exit;
+ }
+ if(v < 0 || v > ADDR_MAX){
+ goto exit;
+ }
+ addr |= (v << shift);
+ if(idx == n) break;
+ shift -= BYTE_BITS;
+ s += idx+1;
+ }
+ err = 0;
+ exit:
+ addr = htonl(addr);
+ *address = (err ? 0 : addr);
+ return err;
+}
+
+#ifdef __KERNEL__
+/** Convert an address in network order to IPv4 dot notation.
+ * The return value is a static buffer which is overwritten on each call.
+ *
+ * @param inaddr address (in network order)
+ * @return address in dot notation
+ */
+char *inet_ntoa(struct in_addr inaddr){
+ static char address[16] = {};
+ uint32_t addr = ntohl(inaddr.s_addr);
+ snprintf(address, sizeof(address), "%d.%d.%d.%d",
+ (unsigned)((addr >> 24) & 0xff),
+ (unsigned)((addr >> 16) & 0xff),
+ (unsigned)((addr >> 8) & 0xff),
+ (unsigned)((addr ) & 0xff));
+ return address;
+}
+
+
+/** Convert a string in IPv4 dot notation to an int in network order.
+ *
+ * @param address address in dot notation
+ * @param inp result of conversion (in network order)
+ * @return 0 on success, error code on error
+ */
+int inet_aton(const char *address, struct in_addr *inp){
+ int err = 0;
+ unsigned long addr;
+
+ err = get_inet_addr(address, &addr);
+ if(err) goto exit;
+ inp->s_addr = addr;
+ exit:
+ return err;
+}
+#endif
+
+/** Convert a hostname or IPv4 address string to an address in network order.
+ *
+ * @param name input hostname or address string
+ * @param address where to put the address
+ * @return 1 if address found OK, 0 otherwise
+ */
+int get_host_address(const char *name, unsigned long *address){
+#ifdef __KERNEL__
+ return get_inet_addr(name, address) == 0;
+#else
+ struct hostent *host = gethostbyname(name);
+ if(!host){
+ return 0;
+ }
+ *address = ((struct in_addr *)(host->h_addr))->s_addr;
+ return 1;
+#endif
+}
+
+/** Convert a service name to a port (in network order).
+ *
+ * @param name service name
+ * @param port where to put the port
+ * @return 1 if service port found OK, 0 otherwise
+ */
+int get_service_port(const char *name, unsigned long *port){
+#ifdef __KERNEL__
+ return 0;
+#else
+ struct servent *service;
+ service = getservbyname(name, 0);
+ if(!service){
+ return 0;
+ }
+ *port = service->s_port;
+ return 1;
+#endif
+}
+
+/** Convert a port number (in network order) to a service name.
+ *
+ * @param port the port number
+ * @return service name if found OK, 0 otherwise
+ */
+char *get_port_service(unsigned long port){
+#ifdef __KERNEL__
+ return 0;
+#else
+ struct servent *service = getservbyport(port, 0);
+ return (service ? service->s_name : 0);
+#endif
+}
+
+/** Convert a decimal integer or service name to a port (in network order).
+ *
+ * @param s input to convert
+ * @param port where to put the port
+ * @return 1 if port found OK, 0 otherwise
+ */
+int convert_service_to_port(const char *s, unsigned long *port){
+ int ok = 0;
+ unsigned long value;
+ if(convert_atoul(s, &value)){
+ ok = get_service_port(s, &value);
+ } else {
+ ok = (0 <= value) && (value <= PORT_MAX);
+ value = htons((unsigned short)value);
+ }
+ *port = (ok ? value : 0);
+ return ok;
+}
+
+#define MAC_ELEMENT_N 6 // Number of elements in a MAC address.
+#define MAC_DIGIT_N 2 // Number of digits in an element in a MAC address.
+#define MAC_LENGTH 17 //((MAC_ELEMENT_N * MAC_DIGIT_N) + MAC_ELEMENT_N - 1)
+
+/** Convert a mac address from a string of the form
+ * XX:XX:XX:XX:XX:XX to numerical form (an array of 6 unsigned chars).
+ * Each X denotes a hex digit: 0..9, a..f, A..F.
+ * Also supports using '-' as the separator instead of ':'.
+ *
+ * @param mac_in string to convert
+ * @param mac destination for the value
+ * @return 0 on success, -1 on error
+ */
+int mac_aton(const char *mac_in, unsigned char *mac){
+ int err = 0;
+ int i, j;
+ const char *p;
+ char sep = 0;
+ unsigned char d;
+ if(!mac_in || strlen(mac_in) != MAC_LENGTH){
+ err = -1;
+ goto exit;
+ }
+ for(i = 0, p = mac_in; i < MAC_ELEMENT_N; i++){
+ d = 0;
+ if(i){
+ if(!sep){
+ if(*p == ':' || *p == '-') sep = *p;
+ }
+ if(sep && *p == sep){
+ p++;
+ } else {
+ err = -1;
+ goto exit;
+ }
+ }
+ for(j = 0; j < MAC_DIGIT_N; j++, p++){
+ if(j) d <<= 4;
+ if(*p >= '0' && *p <= '9'){
+ d += (*p - '0');
+ } else if(*p >= 'A' && *p <= 'F'){
+ d += (*p - 'A') + 10;
+ } else if(*p >= 'a' && *p <= 'f'){
+ d += (*p - 'a') + 10;
+ } else {
+ err = -1;
+ goto exit;
+ }
+ }
+ mac[i] = d;
+ }
+ exit:
+ return err;
+}
+
+/** Convert a MAC address from numerical form to a string.
+ *
+ * @param mac address to convert
+ * @return static string value
+ */
+char *mac_ntoa(const unsigned char *mac){
+ static char buf[MAC_LENGTH + 1];
+ int buf_n = sizeof(buf);
+
+ memset(buf, buf_n, 0);
+ snprintf(buf, buf_n, "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2],
+ mac[3], mac[4], mac[5]);
+ buf[buf_n - 1] = '\0';
+ return buf;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XEN_LIB_SYS_NET_H_
+#define _XEN_LIB_SYS_NET_H_
+/** @file
+ *
+ * Replacement for standard network includes.
+ * Works in user or kernel code.
+ */
+
+extern int get_inet_addr(const char *s, unsigned long *address);
+extern unsigned long bits_to_mask(int n);
+extern int mask_to_bits(unsigned long mask);
+extern int get_host_address(const char *name, unsigned long *address);
+extern int get_service_port(const char *name, unsigned long *port);
+extern char *get_port_service(unsigned long port);
+extern int convert_service_to_port(const char *s, unsigned long *port);
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <asm/byteorder.h>
+
+#ifndef htonl
+#define htonl(x) __constant_htonl(x)
+#endif
+
+#ifndef ntohl
+#define ntohl(x) __constant_ntohl(x)
+#endif
+
+#ifndef htons
+#define htons(x) __constant_htons(x)
+#endif
+
+#ifndef ntohs
+#define ntohs(x) __constant_ntohs(x)
+#endif
+
+#include <linux/in.h>
+extern char *inet_ntoa(struct in_addr inaddr);
+extern int inet_aton(const char *address, struct in_addr *inp);
+
+#else
+
+#include <limits.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#endif
+
+extern char *mac_ntoa(const unsigned char *macaddr);
+extern int mac_aton(const char *addr, unsigned char *macaddr);
+
+#endif /* !_SP_SYS_NET_H_ */
+
+
+
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef __KERNEL__
+# include <linux/config.h>
+# include <linux/module.h>
+# include <linux/kernel.h>
+# include <linux/errno.h>
+#else
+# include <errno.h>
+#endif
+
+#include "allocate.h"
+#include "sys_string.h"
+
+/** Set the base to use for converting a string to a number. Base is
+ * hex if starts with 0x, otherwise decimal.
+ *
+ * @param s input string
+ * @param base where to put the base
+ * @return rest of s to parse as a number
+ */
+inline static const char * convert_set_base(const char *s, int *base){
+ *base = 10;
+ if(s){
+ if(*s=='0'){
+ s++;
+ if(*s=='x' || *s=='X'){
+ *base = 16;
+ s++;
+ }
+ }
+ }
+ return s;
+}
+
+/** Get the numerical value of a digit in the given base.
+ *
+ * @param c digit character
+ * @param base to use
+ * @return numerical value of digit in range 0..base-1 or
+ * -1 if not in range for the base
+ */
+inline static int convert_get_digit(char c, int base){
+ int d;
+
+ if('0'<=c && c<='9'){
+ d = c - '0';
+ } else if('a'<=c && c<='f'){
+ d = c - 'a' + 10;
+ } else if('A'<=c && c<='F'){
+ d = c - 'A' + 10;
+ } else {
+ d = -1;
+ }
+ return (d < base ? d : -1);
+}
+
+/** Convert a string to an unsigned long by parsing it as a number.
+ * Will accept hex or decimal in usual C syntax.
+ *
+ * @param str input string
+ * @param val where to put the result
+ * @return 0 if converted OK, negative otherwise
+ */
+int convert_atoul(const char *str, unsigned long *val){
+ int err = 0;
+ unsigned long v = 0;
+ int base;
+ const char *s = str;
+
+ if(!s) {
+ err = -EINVAL;
+ goto exit;
+ }
+ s = convert_set_base(s, &base);
+ for( ; !err && *s; s++){
+ int digit = convert_get_digit(*s, base);
+ if(digit<0){
+ err = -EINVAL;
+ goto exit;
+ }
+ v *= base;
+ v += digit;
+ }
+ exit:
+ *val = (err ? 0 : v);
+ return err;
+}
+
+/** Combine a directory path with a relative path to produce
+ * a new path.
+ *
+ * @param s directory path
+ * @param t relative path
+ * @return new combined path s/t
+ */
+int path_concat(char *s, char *t, char **val){
+ int err = 0;
+ int sn, tn, vn;
+ char *v;
+ sn = strlen(s);
+ if(sn > 0 && s[sn-1] == '/'){
+ sn--;
+ }
+ tn = strlen(t);
+ if(tn > 0 && t[0] == '/'){
+ tn--;
+ }
+ vn = sn+tn+1;
+ v = (char*)allocate(vn+1);
+ if(!v){
+ err = -ENOMEM;
+ goto exit;
+ }
+ strncpy(v, s, sn);
+ v[sn] = '/';
+ strncpy(v+sn+1, t, tn);
+ v[vn] = '\0';
+ exit:
+ *val = (err ? NULL : v);
+ return err;
+}
--- /dev/null
+/*
+ * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _XEN_LIB_SYS_STRING_H_
+#define _XEN_LIB_SYS_STRING_H_
+/** @file
+ * Replacement for standard string includes.
+ * Works in user or kernel code.
+ */
+/*============================================================================*/
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <stdarg.h>
+#include "allocate.h"
+
+#if 0
+static inline int tolower(int c){
+ return (c>='A' && c<='Z' ? (c-'A')+'a' : c);
+}
+#endif
+
+static inline int isalpha(int c){
+ return (c>='A' && c<='Z') || (c>='a' && c<='z');
+}
+
+static inline int isdigit(int c){
+ return (c>='0' && c<='9');
+}
+
+#if 0
+static inline int strcasecmp(const char *s1, const char *s2){
+ int c1, c2;
+
+ do {
+ c1 = tolower(*s1++);
+ c2 = tolower(*s2++);
+ } while (c1 && c1 == c2);
+ return c1 - c2;
+}
+#endif
+
+static inline char * strdup(const char *s){
+ int n = (s ? 1+strlen(s) : 0);
+ char *copy = (n ? allocate(n) : NULL);
+ if(copy){
+ strcpy(copy, s);
+ }
+ return copy;
+}
+
+/*============================================================================*/
+#else
+#include <string.h>
+#include <stdio.h>
+
+#ifndef _GNU_SOURCE
+static inline size_t strnlen(const char *s, size_t n){
+ int k = 0;
+ if(s){
+ for(k=0; *s && k<n; s++, k++){}
+ }
+ return k;
+}
+#endif
+
+#endif
+/*============================================================================*/
+
+extern int convert_atoul(const char *s, unsigned long *v);
+extern int path_concat(char *s, char *t, char **val);
+
+#endif /* !_XEN_LIB_SYS_STRING_H_ */
--- /dev/null
+/* $Id: xdr.c,v 1.3 2003/09/29 13:40:00 mjw Exp $ */
+#include "xdr.h"
+#include <errno.h>
+/** @file
+ * XDR packer/unpacker for elements.
+ *
+ * string -> [T_STRING] [len:u32] <len bytes>
+ * atom -> [T_ATOM] [len:u32] <len bytes>
+ * uint -> [T_UINT] [value]
+ * cons -> [T_CONS] <car> <cdr>
+ * null -> [T_NULL]
+ * none -> [T_NONE]
+ * bool -> [T_BOOL] { 0:u8 | 1:u8 }
+ *
+ * types packed as u16.
+ *
+ * So (a b c) -> [T_CONS] a [T_CONS] b [T_CONS] c [T_NULL]
+ * () -> [T_NULL]
+ */
+
+int pack_bool(IOStream *io, int x){
+ int err=0;
+ err = IOStream_print(io, "%c", 0xff & x);
+ if(err > 0) err = 0;
+ return err;
+}
+
+int unpack_bool(IOStream *io, int *x){
+ int err = 0;
+ int c;
+ c = IOStream_getc(io);
+ *x = (c < 0 ? 0 : c);
+ err = IOStream_error(io);
+ if(c < 0 && !err) err = -EIO;
+ return err;
+}
+
+int pack_ushort(IOStream *io, unsigned short x){
+ int err=0;
+ err = IOStream_print(io, "%c%c",
+ 0xff & (x >> 8),
+ 0xff & (x ));
+ if(err > 0) err = 0;
+ return err;
+}
+
+int unpack_ushort(IOStream *io, unsigned short *x){
+ int err = 0;
+ int i, c = 0;
+ *x = 0;
+ for(i = 0; i< 2; i++){
+ c = IOStream_getc(io);
+ if(c < 0) break;
+ *x <<= 8;
+ *x |= (0xff & c);
+ }
+ err = IOStream_error(io);
+ if(c < 0 && !err) err = -EIO;
+ return err;
+}
+
+int pack_uint(IOStream *io, unsigned int x){
+ int err=0;
+ err = IOStream_print(io, "%c%c%c%c",
+ 0xff & (x >> 24),
+ 0xff & (x >> 16),
+ 0xff & (x >> 8),
+ 0xff & (x ));
+ if(err > 0) err = 0;
+ return err;
+}
+
+int unpack_uint(IOStream *io, unsigned int *x){
+ int err = 0;
+ int i, c = 0;
+ *x = 0;
+ for(i = 0; i< 4; i++){
+ c = IOStream_getc(io);
+ if(c < 0) break;
+ *x <<= 8;
+ *x |= (0xff & c);
+ }
+ err = IOStream_error(io);
+ if(c < 0 && !err) err = -EIO;
+ return err;
+}
+
+int pack_string(IOStream *io, Sxpr x){
+ int err = 0;
+ int n = string_length(x);
+ char *s = string_string(x);
+ int i;
+ err = pack_uint(io, n);
+ if(err) goto exit;
+ for(i = 0; i < n; i++){
+ err = IOStream_print(io, "%c", s[i]);
+ if(err < 0) break;
+ }
+ if(err > 0) err = 0;
+ exit:
+ return err;
+}
+
+int unpack_string(IOStream *io, Sxpr *x){
+ int err;
+ unsigned int n;
+ int i, c = 0;
+ char *s;
+ Sxpr val = ONONE;
+
+ err = unpack_uint(io, &n);
+ if(err) goto exit;
+ val = halloc(n+1, T_STRING);
+ if(NOMEMP(val)){
+ err = -ENOMEM;
+ goto exit;
+ }
+ s = string_string(val);
+ for(i=0; i<n; i++){
+ c = IOStream_getc(io);
+ if(c < 0) break;
+ s[i] = (char)c;
+ }
+ s[n] = '\0';
+ exit:
+ err = IOStream_error(io);
+ if(c < 0 && !err) err = -EIO;
+ if(err){
+ objfree(val);
+ val = ONONE;
+ }
+ *x = val;
+ return err;
+}
+
+int pack_cons(IOStream *io, Sxpr x){
+ int err = 0;
+ err = pack_sxpr(io, CAR(x));
+ if(err) goto exit;
+ err = pack_sxpr(io, CDR(x));
+ exit:
+ return err;
+}
+
+int unpack_cons(IOStream *io, Sxpr *x){
+ int err = 0;
+ Sxpr u = ONONE, v = ONONE, val = ONONE;
+ err = unpack_sxpr(io, &u);
+ if(err) goto exit;
+ err = unpack_sxpr(io, &v);
+ if(err) goto exit;
+ val = cons_new(u, v);
+ if(NOMEMP(val)){
+ err = -ENOMEM;
+ }
+ exit:
+ if(err){
+ objfree(u);
+ objfree(v);
+ val = ONONE;
+ }
+ *x = val;
+ return err;
+}
+
+int pack_sxpr(IOStream *io, Sxpr x){
+ int err = 0;
+ unsigned short type = get_type(x);
+ err = pack_ushort(io, type);
+ if(err) goto exit;
+ switch(type){
+ case T_NULL:
+ break;
+ case T_NONE:
+ break;
+ break;
+ case T_BOOL:
+ err = pack_bool(io, get_ul(x));
+ break;
+ case T_CONS:
+ err = pack_cons(io, x);
+ break;
+ case T_ATOM:
+ err = pack_string(io, OBJ_ATOM(x)->name);
+ break;
+ case T_STRING:
+ err = pack_string(io, x);
+ break;
+ case T_UINT:
+ err = pack_uint(io, get_ul(x));
+ break;
+ default:
+ err = -EINVAL;
+ IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type);
+ break;
+ }
+ exit:
+ return err;
+}
+
+int unpack_sxpr(IOStream *io, Sxpr *x){
+ int err = 0;
+ unsigned short type;
+ unsigned int u;
+ Sxpr val = ONONE, y;
+
+ err = unpack_ushort(io, &type);
+ if(err) goto exit;
+ switch(type){
+ case T_NULL:
+ val = ONULL;
+ break;
+ case T_NONE:
+ val = ONONE;
+ break;
+ case T_CONS:
+ err = unpack_cons(io, &val);
+ break;
+ case T_BOOL:
+ err = unpack_bool(io, &u);
+ if(err) goto exit;
+ val = (u ? OTRUE : OFALSE);
+ break;
+ case T_ATOM:
+ err = unpack_string(io, &y);
+ if(err) goto exit;
+ val = intern(string_string(y));
+ objfree(y);
+ break;
+ case T_STRING:
+ err = unpack_string(io, &val);
+ break;
+ case T_UINT:
+ err = unpack_uint(io, &u);
+ if(err) goto exit;
+ val = OBJI(type, u);
+ break;
+ default:
+ err = -EINVAL;
+ IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type);
+ break;
+ }
+ exit:
+ *x = (err ? ONONE : val);
+ return err;
+}
--- /dev/null
+/* $Id: xdr.h,v 1.2 2003/09/29 13:40:00 mjw Exp $ */
+#ifndef _SP_XDR_H_
+#define _SP_XDR_H_
+#include "iostream.h"
+#include "sxpr.h"
+int pack_uint(IOStream *out, unsigned int x);
+int unpack_uint(IOStream *in, unsigned int *x);
+int pack_string(IOStream *out, Sxpr x);
+int unpack_string(IOStream *in, Sxpr *x);
+int pack_cons(IOStream *out, Sxpr x);
+int unpack_cons(IOStream *in, Sxpr *x);
+int pack_sxpr(IOStream *out, Sxpr x);
+int unpack_sxpr(IOStream *in, Sxpr *x);
+#endif /* _SP_XDR_H_ */
+XEN_ROOT=../..
+include $(XEN_ROOT)/tools/Make.defs
+
CC = gcc
CFLAGS = -Wall -O3
-EXTRA_INC = -I../../xen/include/hypervisor-ifs
-EXTRA_INC += -I../../linux-xen-sparse/include -I../xc/lib
-EXTRA_INC += -I../xu/lib
-EXTRA_INC += -I../lib
+
+INCLUDES += -I $(XEN_HYPERVISOR_IFS)
+INCLUDES += -I $(XEN_LINUX_INCLUDE)
+INCLUDES += -I $(XEN_XC)
+INCLUDES += -I $(XEN_XU)
+INCLUDES += -I $(XEN_LIBXC)
+INCLUDES += -I $(XEN_LIBXUTIL)
+
+CFLAGS += $(INCLUDES)
HDRS = $(wildcard *.h)
SRCS = $(wildcard *.c)
TARGETS = xen_cpuperf
-INSTALL = $(TARGETS) xencons
+INSTALL_BIN = $(TARGETS) xencons
+INSTALL_SBIN = netfix xm xend
all: $(TARGETS)
$(MAKE) -C miniterm
install: all
mkdir -p $(prefix)/usr/bin
mkdir -p $(prefix)/usr/sbin
- install -m0755 $(INSTALL) $(prefix)/usr/bin
- install -m0755 netfix $(prefix)/usr/sbin
+ install -m0755 $(INSTALL_BIN) $(prefix)/usr/bin
+ install -m0755 $(INSTALL_SBIN) $(prefix)/usr/sbin
$(MAKE) -C miniterm install
clean:
$(MAKE) -C miniterm clean
%: %.c $(HDRS) Makefile
- $(CC) $(CFLAGS) $(EXTRA_INC) -o $@ $<
+ $(CC) $(CFLAGS) -o $@ $<
-#!/usr/bin/python
+#!/usr/bin/env python
# -*- mode: python; -*-
+#============================================================================
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
#============================================================================
# Move the IP address from eth0 onto the Xen bridge (nbe-br).
#============================================================================
from getopt import getopt
-from xen.xend.XendBridge import *
+from xen.util.Brctl import *
short_options = 'hvqni:b:c'
long_options = ['help', 'verbose', 'quiet',
--- /dev/null
+#!/usr/bin/env python
+# -*- mode: python; -*-
+#============================================================================
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+#============================================================================
+
+"""Xen management daemon. Lives in /usr/sbin.
+ Provides console server and HTTP management api.
+
+ Run:
+
+ xend start
+
+ The daemon is stopped with:
+
+ xend stop
+
+ The daemon should reconnect to device control interfaces
+ and recover its state when restarted.
+"""
+import os
+import sys
+from xen.xend.server import SrvDaemon
+
+def main():
+ daemon = SrvDaemon.instance()
+ if not sys.argv[1:]:
+ print 'usage: %s {start|stop|restart}' % sys.argv[0]
+ elif os.fork():
+ pid, status = os.wait()
+ return status >> 8
+ elif sys.argv[1] == 'start':
+ return daemon.start()
+ elif sys.argv[1] == 'trace_start':
+ return daemon.start(trace=1)
+ elif sys.argv[1] == 'stop':
+ return daemon.stop()
+ elif sys.argv[1] == 'restart':
+ return daemon.stop() or daemon.start()
+ else:
+ print 'not an option:', sys.argv[1]
+ return 1
+
+if __name__ == '__main__':
+ sys.exit(main())
--- /dev/null
+#!/usr/bin/env python
+# -*- mode: python; -*-
+import sys
+from xen.xm import main
+
+main.main(sys.argv)
--- /dev/null
+
+all:
+ python setup.py build
+
+install: all
+ if [ "$(prefix)" = "" ]; then \
+ python setup.py install; \
+ elif [ "$(dist)" = "yes" ]; then \
+ python setup.py install --home="$(prefix)"; \
+ else \
+ python setup.py install --root="$(prefix)"; \
+ fi
+
+clean:
+ rm -rf build *.pyc *.pyo *.o *.a *~
--- /dev/null
+
+from distutils.core import setup, Extension
+
+XEN_ROOT = "../.."
+
+extra_compile_args = ["-fno-strict-aliasing"]
+
+
+include_dirs = [ XEN_ROOT + "/xen/include/hypervisor-ifs",
+ XEN_ROOT + "/linux-xen-sparse/include",
+ XEN_ROOT + "/tools/python/xen/ext/xu",
+ XEN_ROOT + "/tools/libxc",
+ XEN_ROOT + "/tools/libxutil",
+ ]
+
+library_dirs = [ XEN_ROOT + "/tools/libxc",
+ XEN_ROOT + "/tools/libxutil",
+ ]
+
+libraries = [ "xc", "xutil" ]
+
+xc = Extension("xc",
+ extra_compile_args = extra_compile_args,
+ include_dirs = include_dirs + [ "xen/ext/xc" ],
+ library_dirs = library_dirs,
+ libraries = libraries,
+ sources = [ "xen/ext/xc/xc.c" ])
+
+xu = Extension("xu",
+ extra_compile_args = extra_compile_args,
+ include_dirs = include_dirs + [ "xen/ext/xu" ],
+ library_dirs = library_dirs,
+ libraries = libraries,
+ sources = [ "xen/ext/xu/xu.c" ])
+
+setup(name = 'xen',
+ version = '2.0',
+ description = 'Xen',
+ packages = ['xen',
+ 'xen.ext',
+ 'xen.util',
+ 'xen.xend',
+ 'xen.xend.server',
+ 'xen.xm',
+ ],
+ ext_package = "xen.ext",
+ ext_modules = [ xc, xu ]
+ )
--- /dev/null
+
+all:
+ python setup.py build
+
+install: all
+ if [ "$(prefix)" = "" ]; then \
+ python setup.py install; \
+ elif [ "$(dist)" = "yes" ]; then \
+ python setup.py install --home="$(prefix)"; \
+ else \
+ python setup.py install --root="$(prefix)"; \
+ fi
+
+clean:
+ rm -rf build *.pyc *.pyo *.o *.a *~
--- /dev/null
+
+from distutils.core import setup, Extension
+
+module = Extension("xc",
+ extra_compile_args = ["-fno-strict-aliasing"],
+ include_dirs = ["../lib",
+ "../../../xen/include/hypervisor-ifs",
+ "../../../linux-xen-sparse/include",
+ "../../xu/lib",
+ "../../lib" ],
+ library_dirs = ["../lib",
+ "../../lib" ],
+ libraries = ["xc"],
+ sources = ["Xc.c"])
+
+setup(name = "xc",
+ version = "2.0",
+ ext_package = "xen.ext",
+ ext_modules = [module])
--- /dev/null
+/******************************************************************************
+ * Xc.c
+ *
+ * Copyright (c) 2003-2004, K A Fraser (University of Cambridge)
+ */
+
+#include <Python.h>
+#include <xc.h>
+#include <zlib.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include "xc_private.h"
+#include "gzip_stream.h"
+
+/* Needed for Python versions earlier than 2.3. */
+#ifndef PyMODINIT_FUNC
+#define PyMODINIT_FUNC DL_EXPORT(void)
+#endif
+
+#define XENPKG "xen.ext.xc"
+
+static PyObject *xc_error, *zero;
+
+typedef struct {
+ PyObject_HEAD;
+ int xc_handle;
+} XcObject;
+
+/*
+ * Definitions for the 'xc' object type.
+ */
+
+static PyObject *pyxc_domain_create(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ unsigned int mem_kb = 0;
+ char *name = "(anon)";
+ int cpu = -1;
+ u32 dom;
+ int ret;
+
+ static char *kwd_list[] = { "mem_kb", "name", "cpu", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|isi", kwd_list,
+ &mem_kb, &name, &cpu) )
+ return NULL;
+
+ if ( (ret = xc_domain_create(xc->xc_handle, mem_kb, name, cpu, &dom)) < 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ return PyInt_FromLong(dom);
+}
+
+static PyObject *pyxc_domain_pause(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ u32 dom;
+
+ static char *kwd_list[] = { "dom", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) )
+ return NULL;
+
+ if ( xc_domain_pause(xc->xc_handle, dom) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_domain_unpause(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ u32 dom;
+
+ static char *kwd_list[] = { "dom", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) )
+ return NULL;
+
+ if ( xc_domain_unpause(xc->xc_handle, dom) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_domain_destroy(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ u32 dom;
+
+ static char *kwd_list[] = { "dom", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) )
+ return NULL;
+
+ if ( xc_domain_destroy(xc->xc_handle, dom) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_domain_pincpu(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ u32 dom;
+ int cpu = -1;
+
+ static char *kwd_list[] = { "dom", "cpu", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
+ &dom, &cpu) )
+ return NULL;
+
+ if ( xc_domain_pincpu(xc->xc_handle, dom, cpu) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_domain_getinfo(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+ PyObject *list;
+
+ u32 first_dom = 0;
+ int max_doms = 1024, nr_doms, i;
+ xc_dominfo_t *info;
+
+ static char *kwd_list[] = { "first_dom", "max_doms", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list,
+ &first_dom, &max_doms) )
+ return NULL;
+
+ if ( (info = malloc(max_doms * sizeof(xc_dominfo_t))) == NULL )
+ return PyErr_NoMemory();
+
+ nr_doms = xc_domain_getinfo(xc->xc_handle, first_dom, max_doms, info);
+
+ list = PyList_New(nr_doms);
+ for ( i = 0 ; i < nr_doms; i++ )
+ {
+ PyList_SetItem(
+ list, i,
+ Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i"
+ ",s:l,s:L,s:s,s:l,s:i}",
+ "dom", info[i].domid,
+ "cpu", info[i].cpu,
+ "dying", info[i].dying,
+ "crashed", info[i].crashed,
+ "shutdown", info[i].shutdown,
+ "paused", info[i].paused,
+ "blocked", info[i].blocked,
+ "running", info[i].running,
+ "mem_kb", info[i].nr_pages*4,
+ "cpu_time", info[i].cpu_time,
+ "name", info[i].name,
+ "maxmem_kb", info[i].max_memkb,
+ "shutdown_reason", info[i].shutdown_reason
+ ));
+ }
+
+ free(info);
+
+ return list;
+}
+
+static int file_save(XcObject *xc, XcIOContext *ctxt, char *state_file){
+ int rc = -1;
+ int fd = -1;
+ int open_flags = (O_CREAT | O_EXCL | O_WRONLY);
+ int open_mode = 0644;
+
+ printf("%s>\n", __FUNCTION__);
+ fd = open(state_file, open_flags, open_mode);
+ if(fd < 0){
+ xcio_perror(ctxt, "Could not open file for writing");
+ goto exit;
+ }
+ /* Compression rate 1: we want speed over compression.
+ * We're mainly going for those zero pages, after all.
+ */
+ printf("%s>gzip_stream_fdopen... \n", __FUNCTION__);
+ ctxt->io = gzip_stream_fdopen(fd, "wb1");
+ if(!ctxt->io){
+ xcio_perror(ctxt, "Could not allocate compression state");
+ goto exit;
+ }
+ printf("%s> xc_linux_save...\n", __FUNCTION__);
+ rc = xc_linux_save(xc->xc_handle, ctxt);
+ exit:
+ if(ctxt->io) IOStream_close(ctxt->io);
+ if(fd >= 0) close(fd);
+ unlink(state_file);
+ printf("%s> rc=%d\n", __FUNCTION__, rc);
+ return rc;
+}
+
+static PyObject *pyxc_linux_save(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ u32 dom;
+ char *state_file;
+ int progress = 1, debug = 0;
+ unsigned int flags = 0;
+ PyObject *val = NULL;
+ int rc = -1;
+ XcIOContext ioctxt = { .info = iostdout, .err = iostderr };
+
+ static char *kwd_list[] = { "dom", "state_file", "vmconfig", "progress", "debug", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "is|sii", kwd_list,
+ &ioctxt.domain,
+ &state_file,
+ &ioctxt.vmconfig,
+ &progress,
+ &debug)){
+ goto exit;
+ }
+ ioctxt.vmconfig_n = (ioctxt.vmconfig ? strlen(ioctxt.vmconfig) : 0);
+ if (progress) ioctxt.flags |= XCFLAGS_VERBOSE;
+ if (debug) ioctxt.flags |= XCFLAGS_DEBUG;
+ if(!state_file || state_file[0] == '\0') goto exit;
+ rc = file_save(xc, &ioctxt, state_file);
+ if(rc){
+ PyErr_SetFromErrno(xc_error);
+ goto exit;
+ }
+ //xc_domain_destroy(xc->xc_handle, dom);
+ Py_INCREF(zero);
+ val = zero;
+ exit:
+ return val;
+}
+
+
+static int file_restore(XcObject *xc, XcIOContext *ioctxt, char *state_file){
+ int rc = -1;
+
+ ioctxt->io = gzip_stream_fopen(state_file, "rb");
+ if (!ioctxt->io) {
+ xcio_perror(ioctxt, "Could not open file for reading");
+ goto exit;
+ }
+
+ rc = xc_linux_restore(xc->xc_handle, ioctxt);
+ exit:
+ if(ioctxt->io) IOStream_close(ioctxt->io);
+ return rc;
+}
+
+static PyObject *pyxc_linux_restore(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+ char *state_file;
+ int progress = 1, debug = 0;
+ u32 dom;
+ PyObject *val = NULL;
+ XcIOContext ioctxt = { .info = iostdout, .err = iostderr };
+ int rc =-1;
+
+ static char *kwd_list[] = { "state_file", "progress", "debug", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "is|ii", kwd_list,
+ &ioctxt.domain,
+ &state_file,
+ &progress,
+ &debug)){
+ goto exit;
+ }
+ if (progress) ioctxt.flags |= XCFLAGS_VERBOSE;
+ if (debug) ioctxt.flags |= XCFLAGS_DEBUG;
+
+ if(!state_file || state_file[0] == '\0') goto exit;
+ rc = file_restore(xc, &ioctxt, state_file);
+ if(rc){
+ PyErr_SetFromErrno(xc_error);
+ goto exit;
+ }
+ val = Py_BuildValue("{s:i,s:s}",
+ "dom", ioctxt.domain,
+ "vmconfig", ioctxt.vmconfig);
+ //? free(ioctxt.vmconfig);
+ exit:
+ return val;
+}
+
+static PyObject *pyxc_linux_build(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ u32 dom;
+ char *image, *ramdisk = NULL, *cmdline = "";
+ int control_evtchn, flags = 0;
+
+ static char *kwd_list[] = { "dom", "control_evtchn",
+ "image", "ramdisk", "cmdline", "flags",
+ NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssi", kwd_list,
+ &dom, &control_evtchn,
+ &image, &ramdisk, &cmdline, &flags) )
+ return NULL;
+
+ if ( xc_linux_build(xc->xc_handle, dom, image,
+ ramdisk, cmdline, control_evtchn, flags) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_netbsd_build(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ u32 dom;
+ char *image, *ramdisk = NULL, *cmdline = "";
+ int control_evtchn;
+
+ static char *kwd_list[] = { "dom", "control_evtchn",
+ "image", "ramdisk", "cmdline", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssi", kwd_list,
+ &dom, &control_evtchn,
+ &image, &ramdisk, &cmdline) )
+ return NULL;
+
+ if ( xc_netbsd_build(xc->xc_handle, dom, image,
+ cmdline, control_evtchn) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_bvtsched_global_set(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ unsigned long ctx_allow;
+
+ static char *kwd_list[] = { "ctx_allow", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "l", kwd_list, &ctx_allow) )
+ return NULL;
+
+ if ( xc_bvtsched_global_set(xc->xc_handle, ctx_allow) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_bvtsched_global_get(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ unsigned long ctx_allow;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ if ( xc_bvtsched_global_get(xc->xc_handle, &ctx_allow) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ return Py_BuildValue("s:l", "ctx_allow", ctx_allow);
+}
+
+static PyObject *pyxc_bvtsched_domain_set(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ u32 dom;
+ unsigned long mcuadv, warp, warpl, warpu;
+
+ static char *kwd_list[] = { "dom", "mcuadv", "warp", "warpl",
+ "warpu", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "illll", kwd_list,
+ &dom, &mcuadv, &warp, &warpl, &warpu) )
+ return NULL;
+
+ if ( xc_bvtsched_domain_set(xc->xc_handle, dom, mcuadv,
+ warp, warpl, warpu) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_bvtsched_domain_get(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+ u32 dom;
+ unsigned long mcuadv, warp, warpl, warpu;
+
+ static char *kwd_list[] = { "dom", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) )
+ return NULL;
+
+ if ( xc_bvtsched_domain_get(xc->xc_handle, dom, &mcuadv, &warp,
+ &warpl, &warpu) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ return Py_BuildValue("{s:i,s:l,s:l,s:l,s:l}",
+ "domain", dom,
+ "mcuadv", mcuadv,
+ "warp", warp,
+ "warpl", warpl,
+ "warpu", warpu);
+}
+
+static PyObject *pyxc_evtchn_bind_interdomain(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ u32 dom1 = DOMID_SELF, dom2 = DOMID_SELF;
+ int port1, port2;
+
+ static char *kwd_list[] = { "dom1", "dom2", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list,
+ &dom1, &dom2) )
+ return NULL;
+
+ if ( xc_evtchn_bind_interdomain(xc->xc_handle, dom1,
+ dom2, &port1, &port2) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ return Py_BuildValue("{s:i,s:i}",
+ "port1", port1,
+ "port2", port2);
+}
+
+static PyObject *pyxc_evtchn_bind_virq(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ int virq, port;
+
+ static char *kwd_list[] = { "virq", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &virq) )
+ return NULL;
+
+ if ( xc_evtchn_bind_virq(xc->xc_handle, virq, &port) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ return PyInt_FromLong(port);
+}
+
+static PyObject *pyxc_evtchn_close(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ u32 dom = DOMID_SELF;
+ int port;
+
+ static char *kwd_list[] = { "port", "dom", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
+ &port, &dom) )
+ return NULL;
+
+ if ( xc_evtchn_close(xc->xc_handle, dom, port) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_evtchn_send(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ int port;
+
+ static char *kwd_list[] = { "port", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &port) )
+ return NULL;
+
+ if ( xc_evtchn_send(xc->xc_handle, port) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_evtchn_status(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+ PyObject *dict;
+
+ u32 dom = DOMID_SELF;
+ int port, ret;
+ xc_evtchn_status_t status;
+
+ static char *kwd_list[] = { "port", "dom", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
+ &port, &dom) )
+ return NULL;
+
+ ret = xc_evtchn_status(xc->xc_handle, dom, port, &status);
+ if ( ret != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ switch ( status.status )
+ {
+ case EVTCHNSTAT_closed:
+ dict = Py_BuildValue("{s:s}",
+ "status", "closed");
+ break;
+ case EVTCHNSTAT_unbound:
+ dict = Py_BuildValue("{s:s}",
+ "status", "unbound");
+ break;
+ case EVTCHNSTAT_interdomain:
+ dict = Py_BuildValue("{s:s,s:i,s:i}",
+ "status", "interdomain",
+ "dom", status.u.interdomain.dom,
+ "port", status.u.interdomain.port);
+ break;
+ case EVTCHNSTAT_pirq:
+ dict = Py_BuildValue("{s:s,s:i}",
+ "status", "pirq",
+ "irq", status.u.pirq);
+ break;
+ case EVTCHNSTAT_virq:
+ dict = Py_BuildValue("{s:s,s:i}",
+ "status", "virq",
+ "irq", status.u.virq);
+ break;
+ default:
+ dict = Py_BuildValue("{}");
+ break;
+ }
+
+ return dict;
+}
+
+static PyObject *pyxc_physdev_pci_access_modify(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+ u32 dom;
+ int bus, dev, func, enable, ret;
+
+ static char *kwd_list[] = { "dom", "bus", "dev", "func", "enable", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiii", kwd_list,
+ &dom, &bus, &dev, &func, &enable) )
+ return NULL;
+
+ ret = xc_physdev_pci_access_modify(
+ xc->xc_handle, dom, bus, dev, func, enable);
+ if ( ret != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_readconsolering(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ unsigned int clear = 0;
+ char str[32768];
+ int ret;
+
+ static char *kwd_list[] = { "clear", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &clear) )
+ return NULL;
+
+ ret = xc_readconsolering(xc->xc_handle, str, sizeof(str), clear);
+ if ( ret < 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ return PyString_FromStringAndSize(str, ret);
+}
+
+static PyObject *pyxc_physinfo(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+ xc_physinfo_t info;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ if ( xc_physinfo(xc->xc_handle, &info) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ return Py_BuildValue("{s:i,s:i,s:l,s:l,s:l}",
+ "ht_per_core", info.ht_per_core,
+ "cores", info.cores,
+ "total_pages", info.total_pages,
+ "free_pages", info.free_pages,
+ "cpu_khz", info.cpu_khz);
+}
+
+static PyObject *pyxc_atropos_domain_set(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+ u32 domid;
+ u64 period, slice, latency;
+ int xtratime;
+
+ static char *kwd_list[] = { "dom", "period", "slice", "latency",
+ "xtratime", NULL };
+
+ if( !PyArg_ParseTupleAndKeywords(args, kwds, "iLLLi", kwd_list, &domid,
+ &period, &slice, &latency, &xtratime) )
+ return NULL;
+
+ if ( xc_atropos_domain_set(xc->xc_handle, domid, period, slice,
+ latency, xtratime) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_atropos_domain_get(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+ u32 domid;
+ u64 period, slice, latency;
+ int xtratime;
+
+ static char *kwd_list[] = { "dom", NULL };
+
+ if( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &domid) )
+ return NULL;
+
+ if ( xc_atropos_domain_get( xc->xc_handle, domid, &period,
+ &slice, &latency, &xtratime ) )
+ return PyErr_SetFromErrno(xc_error);
+
+ return Py_BuildValue("{s:i,s:L,s:L,s:L,s:i}",
+ "domain", domid,
+ "period", period,
+ "slice", slice,
+ "latency", latency,
+ "xtratime", xtratime);
+}
+
+
+static PyObject *pyxc_rrobin_global_set(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+ u64 slice;
+
+ static char *kwd_list[] = { "slice", NULL };
+
+ if( !PyArg_ParseTupleAndKeywords(args, kwds, "L", kwd_list, &slice) )
+ return NULL;
+
+ if ( xc_rrobin_global_set(xc->xc_handle, slice) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_shadow_control(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ u32 dom;
+ int op=0;
+
+ static char *kwd_list[] = { "dom", "op", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
+ &dom, &op) )
+ return NULL;
+
+ if ( xc_shadow_control(xc->xc_handle, dom, op, NULL, 0, NULL) < 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_rrobin_global_get(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+ u64 slice;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ if ( xc_rrobin_global_get(xc->xc_handle, &slice) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ return Py_BuildValue("{s:L}", "slice", slice);
+}
+
+static PyObject *pyxc_domain_setname(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+ u32 dom;
+ char *name;
+
+ static char *kwd_list[] = { "dom", "name", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is", kwd_list,
+ &dom, &name) )
+ return NULL;
+
+ if ( xc_domain_setname(xc->xc_handle, dom, name) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_domain_setmaxmem(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ u32 dom;
+ unsigned long max_memkb;
+
+ static char *kwd_list[] = { "dom", "max_memkb", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list,
+ &dom, &max_memkb) )
+ return NULL;
+
+ if ( xc_domain_setmaxmem(xc->xc_handle, dom, max_memkb) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+
+static PyMethodDef pyxc_methods[] = {
+ { "domain_create",
+ (PyCFunction)pyxc_domain_create,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Create a new domain.\n"
+ " mem_kb [int, 0]: Memory allocation, in kilobytes.\n"
+ " name [str, '(anon)']: Informative textual name.\n\n"
+ "Returns: [int] new domain identifier; -1 on error.\n" },
+
+ { "domain_pause",
+ (PyCFunction)pyxc_domain_pause,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Temporarily pause execution of a domain.\n"
+ " dom [int]: Identifier of domain to be paused.\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "domain_unpause",
+ (PyCFunction)pyxc_domain_unpause,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "(Re)start execution of a domain.\n"
+ " dom [int]: Identifier of domain to be unpaused.\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "domain_destroy",
+ (PyCFunction)pyxc_domain_destroy,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Destroy a domain.\n"
+ " dom [int]: Identifier of domain to be destroyed.\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "domain_pincpu",
+ (PyCFunction)pyxc_domain_pincpu,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Pin a domain to a specified CPU.\n"
+ " dom [int]: Identifier of domain to be pinned.\n"
+ " cpu [int, -1]: CPU to pin to, or -1 to unpin\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "domain_getinfo",
+ (PyCFunction)pyxc_domain_getinfo,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Get information regarding a set of domains, in increasing id order.\n"
+ " first_dom [int, 0]: First domain to retrieve info about.\n"
+ " max_doms [int, 1024]: Maximum number of domains to retrieve info"
+ " about.\n\n"
+ "Returns: [list of dicts] if list length is less than 'max_doms'\n"
+ " parameter then there was an error, or the end of the\n"
+ " domain-id space was reached.\n"
+ " dom [int]: Identifier of domain to which this info pertains\n"
+ " cpu [int]: CPU to which this domain is bound\n"
+ " dying [int]: Bool - is the domain dying?\n"
+ " crashed [int]: Bool - has the domain crashed?\n"
+ " shutdown [int]: Bool - has the domain shut itself down?\n"
+ " paused [int]: Bool - is the domain paused by control software?\n"
+ " blocked [int]: Bool - is the domain blocked waiting for an event?\n"
+ " running [int]: Bool - is the domain currently running?\n"
+ " mem_kb [int]: Memory reservation, in kilobytes\n"
+ " cpu_time [long]: CPU time consumed, in nanoseconds\n"
+ " name [str]: Identifying name\n"
+ " shutdown_reason [int]: Numeric code from guest OS, explaining "
+ "reason why it shut itself down.\n" },
+
+ { "linux_save",
+ (PyCFunction)pyxc_linux_save,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Save the CPU and memory state of a Linux guest OS.\n"
+ " dom [int]: Identifier of domain to be saved.\n"
+ " state_file [str]: Name of state file. Must not currently exist.\n"
+ " progress [int, 1]: Bool - display a running progress indication?\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "linux_restore",
+ (PyCFunction)pyxc_linux_restore,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Restore the CPU and memory state of a Linux guest OS.\n"
+ " state_file [str]: Name of state file. Must not currently exist.\n"
+ " progress [int, 1]: Bool - display a running progress indication?\n\n"
+ "Returns: [int] new domain identifier on success; -1 on error.\n" },
+
+ { "linux_build",
+ (PyCFunction)pyxc_linux_build,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Build a new Linux guest OS.\n"
+ " dom [int]: Identifier of domain to build into.\n"
+ " image [str]: Name of kernel image file. May be gzipped.\n"
+ " ramdisk [str, n/a]: Name of ramdisk file, if any.\n"
+ " cmdline [str, n/a]: Kernel parameters, if any.\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "netbsd_build",
+ (PyCFunction)pyxc_netbsd_build,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Build a new NetBSD guest OS.\n"
+ " dom [int]: Identifier of domain to build into.\n"
+ " image [str]: Name of kernel image file. May be gzipped.\n"
+ " cmdline [str, n/a]: Kernel parameters, if any.\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "bvtsched_global_set",
+ (PyCFunction)pyxc_bvtsched_global_set,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Set global tuning parameters for Borrowed Virtual Time scheduler.\n"
+ " ctx_allow [int]: Minimal guaranteed quantum.\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "bvtsched_global_get",
+ (PyCFunction)pyxc_bvtsched_global_get,
+ METH_KEYWORDS, "\n"
+ "Get global tuning parameters for BVT scheduler.\n"
+ "Returns: [dict]:\n"
+ " ctx_allow [int]: context switch allowance\n" },
+
+ { "bvtsched_domain_set",
+ (PyCFunction)pyxc_bvtsched_domain_set,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Set per-domain tuning parameters for Borrowed Virtual Time scheduler.\n"
+ " dom [int]: Identifier of domain to be tuned.\n"
+ " mcuadv [int]: Proportional to the inverse of the domain's weight.\n"
+ " warp [int]: How far to warp domain's EVT on unblock.\n"
+ " warpl [int]: How long the domain can run warped.\n"
+ " warpu [int]: How long before the domain can warp again.\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "bvtsched_domain_get",
+ (PyCFunction)pyxc_bvtsched_domain_get,
+ METH_KEYWORDS, "\n"
+ "Get per-domain tuning parameters under the BVT scheduler.\n"
+ " dom [int]: Identifier of domain to be queried.\n"
+ "Returns [dict]:\n"
+ " domain [int]: Domain ID.\n"
+ " mcuadv [long]: MCU Advance.\n"
+ " warp [long]: Warp.\n"
+ " warpu [long]: Unwarp requirement.\n"
+ " warpl [long]: Warp limit,\n"
+ },
+
+ { "atropos_domain_set",
+ (PyCFunction)pyxc_atropos_domain_set,
+ METH_KEYWORDS, "\n"
+ "Set the scheduling parameters for a domain when running with Atropos.\n"
+ " dom [int]: domain to set\n"
+ " period [long]: domain's scheduling period\n"
+ " slice [long]: domain's slice per period\n"
+ " latency [long]: wakeup latency hint\n"
+ " xtratime [int]: boolean\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "atropos_domain_get",
+ (PyCFunction)pyxc_atropos_domain_get,
+ METH_KEYWORDS, "\n"
+ "Get the current scheduling parameters for a domain when running with\n"
+ "the Atropos scheduler."
+ " dom [int]: domain to query\n"
+ "Returns: [dict]\n"
+ " domain [int]: domain ID\n"
+ " period [long]: scheduler period\n"
+ " slice [long]: CPU reservation per period\n"
+ " latency [long]: unblocking latency hint\n"
+ " xtratime [int] : 0 if not using slack time, nonzero otherwise\n" },
+
+ { "rrobin_global_set",
+ (PyCFunction)pyxc_rrobin_global_set,
+ METH_KEYWORDS, "\n"
+ "Set Round Robin scheduler slice.\n"
+ " slice [long]: Round Robin scheduler slice\n"
+ "Returns: [int] 0 on success, throws an exception on failure\n" },
+
+ { "rrobin_global_get",
+ (PyCFunction)pyxc_rrobin_global_get,
+ METH_KEYWORDS, "\n"
+ "Get Round Robin scheduler settings\n"
+ "Returns [dict]:\n"
+ " slice [long]: Scheduler time slice.\n" },
+
+ { "evtchn_bind_interdomain",
+ (PyCFunction)pyxc_evtchn_bind_interdomain,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Open an event channel between two domains.\n"
+ " dom1 [int, SELF]: First domain to be connected.\n"
+ " dom2 [int, SELF]: Second domain to be connected.\n\n"
+ "Returns: [dict] dictionary is empty on failure.\n"
+ " port1 [int]: Port-id for endpoint at dom1.\n"
+ " port2 [int]: Port-id for endpoint at dom2.\n" },
+
+ { "evtchn_bind_virq",
+ (PyCFunction)pyxc_evtchn_bind_virq,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Bind an event channel to the specified VIRQ.\n"
+ " virq [int]: VIRQ to bind.\n\n"
+ "Returns: [int] Bound event-channel port.\n" },
+
+ { "evtchn_close",
+ (PyCFunction)pyxc_evtchn_close,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Close an event channel.\n"
+ " dom [int, SELF]: Dom-id of one endpoint of the channel.\n"
+ " port [int]: Port-id of one endpoint of the channel.\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "evtchn_send",
+ (PyCFunction)pyxc_evtchn_send,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Send an event along a locally-connected event channel.\n"
+ " port [int]: Port-id of a local channel endpoint.\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "evtchn_status",
+ (PyCFunction)pyxc_evtchn_status,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Query the status of an event channel.\n"
+ " dom [int, SELF]: Dom-id of one endpoint of the channel.\n"
+ " port [int]: Port-id of one endpoint of the channel.\n\n"
+ "Returns: [dict] dictionary is empty on failure.\n"
+ " status [str]: 'closed', 'unbound', 'interdomain', 'pirq',"
+ " or 'virq'.\n"
+ "The following are returned if 'status' is 'interdomain':\n"
+ " dom [int]: Dom-id of remote endpoint.\n"
+ " port [int]: Port-id of remote endpoint.\n"
+ "The following are returned if 'status' is 'pirq' or 'virq':\n"
+ " irq [int]: IRQ number.\n" },
+
+ { "physdev_pci_access_modify",
+ (PyCFunction)pyxc_physdev_pci_access_modify,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Allow a domain access to a PCI device\n"
+ " dom [int]: Identifier of domain to be allowed access.\n"
+ " bus [int]: PCI bus\n"
+ " dev [int]: PCI slot\n"
+ " func [int]: PCI function\n"
+ " enable [int]: Non-zero means enable access; else disable access\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "readconsolering",
+ (PyCFunction)pyxc_readconsolering,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Read Xen's console ring.\n"
+ " clear [int, 0]: Bool - clear the ring after reading from it?\n\n"
+ "Returns: [str] string is empty on failure.\n" },
+
+ { "physinfo",
+ (PyCFunction)pyxc_physinfo,
+ METH_VARARGS, "\n"
+ "Get information about the physical host machine\n"
+ "Returns [dict]: information about the hardware"
+ " [None]: on failure.\n" },
+
+ { "shadow_control",
+ (PyCFunction)pyxc_shadow_control,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Set parameter for shadow pagetable interface\n"
+ " dom [int]: Identifier of domain.\n"
+ " op [int, 0]: operation\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "domain_setname",
+ (PyCFunction)pyxc_domain_setname,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Set domain informative textual name\n"
+ " dom [int]: Identifier of domain.\n"
+ " name [str]: Text string.\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "domain_setmaxmem",
+ (PyCFunction)pyxc_domain_setname,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Set a domain's memory limit\n"
+ " dom [int]: Identifier of domain.\n"
+ " max_memkb [long]: .\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { NULL, NULL, 0, NULL }
+};
+
+
+/*
+ * Definitions for the 'Xc' module wrapper.
+ */
+
+staticforward PyTypeObject PyXcType;
+
+static PyObject *PyXc_new(PyObject *self, PyObject *args)
+{
+ XcObject *xc;
+
+ if ( !PyArg_ParseTuple(args, ":new") )
+ return NULL;
+
+ xc = PyObject_New(XcObject, &PyXcType);
+
+ if ( (xc->xc_handle = xc_interface_open()) == -1 )
+ {
+ PyObject_Del((PyObject *)xc);
+ return PyErr_SetFromErrno(xc_error);
+ }
+
+ return (PyObject *)xc;
+}
+
+static PyObject *PyXc_getattr(PyObject *obj, char *name)
+{
+ return Py_FindMethod(pyxc_methods, obj, name);
+}
+
+static void PyXc_dealloc(PyObject *self)
+{
+ XcObject *xc = (XcObject *)self;
+ (void)xc_interface_close(xc->xc_handle);
+ PyObject_Del(self);
+}
+
+static PyTypeObject PyXcType = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "Xc",
+ sizeof(XcObject),
+ 0,
+ PyXc_dealloc, /* tp_dealloc */
+ NULL, /* tp_print */
+ PyXc_getattr, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+ NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ NULL /* tp_hash */
+};
+
+static PyMethodDef PyXc_methods[] = {
+ { "new", PyXc_new, METH_VARARGS, "Create a new " XENPKG " object." },
+ { NULL, NULL, 0, NULL }
+};
+
+PyMODINIT_FUNC initxc(void)
+{
+ PyObject *m, *d;
+
+ m = Py_InitModule(XENPKG, PyXc_methods);
+
+ d = PyModule_GetDict(m);
+ xc_error = PyErr_NewException(XENPKG ".error", NULL, NULL);
+ PyDict_SetItemString(d, "error", xc_error);
+
+ zero = PyInt_FromLong(0);
+}
--- /dev/null
+/******************************************************************************
+ * domain_controller.h
+ *
+ * Interface to server controller (e.g., 'xend'). This header file defines the
+ * interface that is shared with guest OSes.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __DOMAIN_CONTROLLER_H__
+#define __DOMAIN_CONTROLLER_H__
+
+
+#ifndef BASIC_START_INFO
+#error "Xen header file hypervisor-if.h must already be included here."
+#endif
+
+
+/*
+ * EXTENDED BOOTSTRAP STRUCTURE FOR NEW DOMAINS.
+ */
+
+typedef struct {
+ BASIC_START_INFO;
+ u16 domain_controller_evtchn; /* 320 */
+} PACKED extended_start_info_t; /* 322 bytes */
+#define SIF_BLK_BE_DOMAIN (1<<4) /* Is this a block backend domain? */
+#define SIF_NET_BE_DOMAIN (1<<5) /* Is this a net backend domain? */
+
+
+/*
+ * Reason codes for SCHEDOP_shutdown. These are opaque to Xen but may be
+ * interpreted by control software to determine the appropriate action. These
+ * are only really advisories: the controller can actually do as it likes.
+ */
+#define SHUTDOWN_poweroff 0 /* Domain exited normally. Clean up and kill. */
+#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */
+#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */
+
+
+/*
+ * CONTROLLER MESSAGING INTERFACE.
+ */
+
+typedef struct {
+ u8 type; /* 0: echoed in response */
+ u8 subtype; /* 1: echoed in response */
+ u8 id; /* 2: echoed in response */
+ u8 length; /* 3: number of bytes in 'msg' */
+ u8 msg[60]; /* 4: type-specific message data */
+} PACKED control_msg_t; /* 64 bytes */
+
+#define CONTROL_RING_SIZE 8
+typedef u32 CONTROL_RING_IDX;
+#define MASK_CONTROL_IDX(_i) ((_i)&(CONTROL_RING_SIZE-1))
+
+typedef struct {
+ control_msg_t tx_ring[CONTROL_RING_SIZE]; /* 0: guest -> controller */
+ control_msg_t rx_ring[CONTROL_RING_SIZE]; /* 512: controller -> guest */
+ CONTROL_RING_IDX tx_req_prod, tx_resp_prod; /* 1024, 1028 */
+ CONTROL_RING_IDX rx_req_prod, rx_resp_prod; /* 1032, 1036 */
+} PACKED control_if_t; /* 1040 bytes */
+
+/*
+ * Top-level command types.
+ */
+#define CMSG_CONSOLE 0 /* Console */
+#define CMSG_BLKIF_BE 1 /* Block-device backend */
+#define CMSG_BLKIF_FE 2 /* Block-device frontend */
+#define CMSG_NETIF_BE 3 /* Network-device backend */
+#define CMSG_NETIF_FE 4 /* Network-device frontend */
+#define CMSG_SHUTDOWN 6 /* Shutdown messages */
+
+
+/******************************************************************************
+ * CONSOLE DEFINITIONS
+ */
+
+/*
+ * Subtypes for console messages.
+ */
+#define CMSG_CONSOLE_DATA 0
+
+
+/******************************************************************************
+ * BLOCK-INTERFACE FRONTEND DEFINITIONS
+ */
+
+/* Messages from domain controller to guest. */
+#define CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED 0
+
+/* Messages from guest to domain controller. */
+#define CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED 32
+#define CMSG_BLKIF_FE_INTERFACE_CONNECT 33
+#define CMSG_BLKIF_FE_INTERFACE_DISCONNECT 34
+
+/* These are used by both front-end and back-end drivers. */
+#define blkif_vdev_t u16
+#define blkif_pdev_t u16
+#define blkif_sector_t u64
+
+/*
+ * CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED:
+ * Notify a guest about a status change on one of its block interfaces.
+ * If the interface is DESTROYED or DOWN then the interface is disconnected:
+ * 1. The shared-memory frame is available for reuse.
+ * 2. Any unacknowledged messgaes pending on the interface were dropped.
+ */
+#define BLKIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */
+#define BLKIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */
+#define BLKIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */
+typedef struct {
+ u32 handle; /* 0 */
+ u32 status; /* 4 */
+ u16 evtchn; /* 8: (only if status == BLKIF_INTERFACE_STATUS_CONNECTED). */
+} PACKED blkif_fe_interface_status_changed_t; /* 10 bytes */
+
+/*
+ * CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED:
+ * Notify the domain controller that the front-end driver is DOWN or UP.
+ * When the driver goes DOWN then the controller will send no more
+ * status-change notifications. When the driver comes UP then the controller
+ * will send a notification for each interface that currently exists.
+ * If the driver goes DOWN while interfaces are still UP, the domain
+ * will automatically take the interfaces DOWN.
+ */
+#define BLKIF_DRIVER_STATUS_DOWN 0
+#define BLKIF_DRIVER_STATUS_UP 1
+typedef struct {
+ /* IN */
+ u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */
+ /* OUT */
+ /*
+ * Tells driver how many interfaces it should expect to immediately
+ * receive notifications about.
+ */
+ u32 nr_interfaces; /* 4 */
+} PACKED blkif_fe_driver_status_changed_t; /* 8 bytes */
+
+/*
+ * CMSG_BLKIF_FE_INTERFACE_CONNECT:
+ * If successful, the domain controller will acknowledge with a
+ * STATUS_CONNECTED message.
+ */
+typedef struct {
+ u32 handle; /* 0 */
+ u32 __pad;
+ memory_t shmem_frame; /* 8 */
+ MEMORY_PADDING;
+} PACKED blkif_fe_interface_connect_t; /* 16 bytes */
+
+/*
+ * CMSG_BLKIF_FE_INTERFACE_DISCONNECT:
+ * If successful, the domain controller will acknowledge with a
+ * STATUS_DISCONNECTED message.
+ */
+typedef struct {
+ u32 handle; /* 0 */
+} PACKED blkif_fe_interface_disconnect_t; /* 4 bytes */
+
+
+/******************************************************************************
+ * BLOCK-INTERFACE BACKEND DEFINITIONS
+ */
+
+/* Messages from domain controller. */
+#define CMSG_BLKIF_BE_CREATE 0 /* Create a new block-device interface. */
+#define CMSG_BLKIF_BE_DESTROY 1 /* Destroy a block-device interface. */
+#define CMSG_BLKIF_BE_CONNECT 2 /* Connect i/f to remote driver. */
+#define CMSG_BLKIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */
+#define CMSG_BLKIF_BE_VBD_CREATE 4 /* Create a new VBD for an interface. */
+#define CMSG_BLKIF_BE_VBD_DESTROY 5 /* Delete a VBD from an interface. */
+#define CMSG_BLKIF_BE_VBD_GROW 6 /* Append an extent to a given VBD. */
+#define CMSG_BLKIF_BE_VBD_SHRINK 7 /* Remove last extent from a given VBD. */
+
+/* Messages to domain controller. */
+#define CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED 32
+
+/*
+ * Message request/response definitions for block-device messages.
+ */
+
+typedef struct {
+ blkif_sector_t sector_start; /* 0 */
+ blkif_sector_t sector_length; /* 8 */
+ blkif_pdev_t device; /* 16 */
+ u16 __pad; /* 18 */
+} PACKED blkif_extent_t; /* 20 bytes */
+
+/* Non-specific 'okay' return. */
+#define BLKIF_BE_STATUS_OKAY 0
+/* Non-specific 'error' return. */
+#define BLKIF_BE_STATUS_ERROR 1
+/* The following are specific error returns. */
+#define BLKIF_BE_STATUS_INTERFACE_EXISTS 2
+#define BLKIF_BE_STATUS_INTERFACE_NOT_FOUND 3
+#define BLKIF_BE_STATUS_INTERFACE_CONNECTED 4
+#define BLKIF_BE_STATUS_VBD_EXISTS 5
+#define BLKIF_BE_STATUS_VBD_NOT_FOUND 6
+#define BLKIF_BE_STATUS_OUT_OF_MEMORY 7
+#define BLKIF_BE_STATUS_EXTENT_NOT_FOUND 8
+#define BLKIF_BE_STATUS_MAPPING_ERROR 9
+
+/* This macro can be used to create an array of descriptive error strings. */
+#define BLKIF_BE_STATUS_ERRORS { \
+ "Okay", \
+ "Non-specific error", \
+ "Interface already exists", \
+ "Interface not found", \
+ "Interface is still connected", \
+ "VBD already exists", \
+ "VBD not found", \
+ "Out of memory", \
+ "Extent not found for VBD", \
+ "Could not map domain memory" }
+
+/*
+ * CMSG_BLKIF_BE_CREATE:
+ * When the driver sends a successful response then the interface is fully
+ * created. The controller will send a DOWN notification to the front-end
+ * driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Domain attached to new interface. */
+ u32 blkif_handle; /* 4: Domain-specific interface handle. */
+ /* OUT */
+ u32 status; /* 8 */
+} PACKED blkif_be_create_t; /* 12 bytes */
+
+/*
+ * CMSG_BLKIF_BE_DESTROY:
+ * When the driver sends a successful response then the interface is fully
+ * torn down. The controller will send a DESTROYED notification to the
+ * front-end driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Identify interface to be destroyed. */
+ u32 blkif_handle; /* 4: ...ditto... */
+ /* OUT */
+ u32 status; /* 8 */
+} PACKED blkif_be_destroy_t; /* 12 bytes */
+
+/*
+ * CMSG_BLKIF_BE_CONNECT:
+ * When the driver sends a successful response then the interface is fully
+ * connected. The controller will send a CONNECTED notification to the
+ * front-end driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Domain attached to new interface. */
+ u32 blkif_handle; /* 4: Domain-specific interface handle. */
+ memory_t shmem_frame; /* 8: Page cont. shared comms window. */
+ MEMORY_PADDING;
+ u32 evtchn; /* 16: Event channel for notifications. */
+ /* OUT */
+ u32 status; /* 20 */
+} PACKED blkif_be_connect_t; /* 24 bytes */
+
+/*
+ * CMSG_BLKIF_BE_DISCONNECT:
+ * When the driver sends a successful response then the interface is fully
+ * disconnected. The controller will send a DOWN notification to the front-end
+ * driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Domain attached to new interface. */
+ u32 blkif_handle; /* 4: Domain-specific interface handle. */
+ /* OUT */
+ u32 status; /* 8 */
+} PACKED blkif_be_disconnect_t; /* 12 bytes */
+
+/* CMSG_BLKIF_BE_VBD_CREATE */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Identify blkdev interface. */
+ u32 blkif_handle; /* 4: ...ditto... */
+ blkif_vdev_t vdevice; /* 8: Interface-specific id for this VBD. */
+ u16 readonly; /* 10: Non-zero -> VBD isn't writeable. */
+ /* OUT */
+ u32 status; /* 12 */
+} PACKED blkif_be_vbd_create_t; /* 16 bytes */
+
+/* CMSG_BLKIF_BE_VBD_DESTROY */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Identify blkdev interface. */
+ u32 blkif_handle; /* 4: ...ditto... */
+ blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */
+ u16 __pad; /* 10 */
+ /* OUT */
+ u32 status; /* 12 */
+} PACKED blkif_be_vbd_destroy_t; /* 16 bytes */
+
+/* CMSG_BLKIF_BE_VBD_GROW */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Identify blkdev interface. */
+ u32 blkif_handle; /* 4: ...ditto... */
+ blkif_extent_t extent; /* 8: Physical extent to append to VBD. */
+ blkif_vdev_t vdevice; /* 28: Interface-specific id of the VBD. */
+ u16 __pad; /* 30 */
+ /* OUT */
+ u32 status; /* 32 */
+} PACKED blkif_be_vbd_grow_t; /* 36 bytes */
+
+/* CMSG_BLKIF_BE_VBD_SHRINK */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Identify blkdev interface. */
+ u32 blkif_handle; /* 4: ...ditto... */
+ blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */
+ u16 __pad; /* 10 */
+ /* OUT */
+ u32 status; /* 12 */
+} PACKED blkif_be_vbd_shrink_t; /* 16 bytes */
+
+/*
+ * CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED:
+ * Notify the domain controller that the back-end driver is DOWN or UP.
+ * If the driver goes DOWN while interfaces are still UP, the controller
+ * will automatically send DOWN notifications.
+ */
+typedef struct {
+ u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */
+} PACKED blkif_be_driver_status_changed_t; /* 4 bytes */
+
+
+/******************************************************************************
+ * NETWORK-INTERFACE FRONTEND DEFINITIONS
+ */
+
+/* Messages from domain controller to guest. */
+#define CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED 0
+
+/* Messages from guest to domain controller. */
+#define CMSG_NETIF_FE_DRIVER_STATUS_CHANGED 32
+#define CMSG_NETIF_FE_INTERFACE_CONNECT 33
+#define CMSG_NETIF_FE_INTERFACE_DISCONNECT 34
+
+/*
+ * CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED:
+ * Notify a guest about a status change on one of its network interfaces.
+ * If the interface is DESTROYED or DOWN then the interface is disconnected:
+ * 1. The shared-memory frame is available for reuse.
+ * 2. Any unacknowledged messgaes pending on the interface were dropped.
+ */
+#define NETIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */
+#define NETIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */
+#define NETIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */
+typedef struct {
+ u32 handle; /* 0 */
+ u32 status; /* 4 */
+ u16 evtchn; /* 8: status == NETIF_INTERFACE_STATUS_CONNECTED */
+ u8 mac[6]; /* 10: status == NETIF_INTERFACE_STATUS_CONNECTED */
+} PACKED netif_fe_interface_status_changed_t; /* 16 bytes */
+
+/*
+ * CMSG_NETIF_FE_DRIVER_STATUS_CHANGED:
+ * Notify the domain controller that the front-end driver is DOWN or UP.
+ * When the driver goes DOWN then the controller will send no more
+ * status-change notifications. When the driver comes UP then the controller
+ * will send a notification for each interface that currently exists.
+ * If the driver goes DOWN while interfaces are still UP, the domain
+ * will automatically take the interfaces DOWN.
+ */
+#define NETIF_DRIVER_STATUS_DOWN 0
+#define NETIF_DRIVER_STATUS_UP 1
+typedef struct {
+ /* IN */
+ u32 status; /* 0: NETIF_DRIVER_STATUS_??? */
+ /* OUT */
+ /*
+ * Tells driver how many interfaces it should expect to immediately
+ * receive notifications about.
+ */
+ u32 nr_interfaces; /* 4 */
+} PACKED netif_fe_driver_status_changed_t; /* 8 bytes */
+
+/*
+ * CMSG_NETIF_FE_INTERFACE_CONNECT:
+ * If successful, the domain controller will acknowledge with a
+ * STATUS_CONNECTED message.
+ */
+typedef struct {
+ u32 handle; /* 0 */
+ u32 __pad; /* 4 */
+ memory_t tx_shmem_frame; /* 8 */
+ MEMORY_PADDING;
+ memory_t rx_shmem_frame; /* 16 */
+ MEMORY_PADDING;
+} PACKED netif_fe_interface_connect_t; /* 24 bytes */
+
+/*
+ * CMSG_NETIF_FE_INTERFACE_DISCONNECT:
+ * If successful, the domain controller will acknowledge with a
+ * STATUS_DISCONNECTED message.
+ */
+typedef struct {
+ u32 handle; /* 0 */
+} PACKED netif_fe_interface_disconnect_t; /* 4 bytes */
+
+
+/******************************************************************************
+ * NETWORK-INTERFACE BACKEND DEFINITIONS
+ */
+
+/* Messages from domain controller. */
+#define CMSG_NETIF_BE_CREATE 0 /* Create a new net-device interface. */
+#define CMSG_NETIF_BE_DESTROY 1 /* Destroy a net-device interface. */
+#define CMSG_NETIF_BE_CONNECT 2 /* Connect i/f to remote driver. */
+#define CMSG_NETIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */
+
+/* Messages to domain controller. */
+#define CMSG_NETIF_BE_DRIVER_STATUS_CHANGED 32
+
+/*
+ * Message request/response definitions for net-device messages.
+ */
+
+/* Non-specific 'okay' return. */
+#define NETIF_BE_STATUS_OKAY 0
+/* Non-specific 'error' return. */
+#define NETIF_BE_STATUS_ERROR 1
+/* The following are specific error returns. */
+#define NETIF_BE_STATUS_INTERFACE_EXISTS 2
+#define NETIF_BE_STATUS_INTERFACE_NOT_FOUND 3
+#define NETIF_BE_STATUS_INTERFACE_CONNECTED 4
+#define NETIF_BE_STATUS_OUT_OF_MEMORY 5
+#define NETIF_BE_STATUS_MAPPING_ERROR 6
+
+/* This macro can be used to create an array of descriptive error strings. */
+#define NETIF_BE_STATUS_ERRORS { \
+ "Okay", \
+ "Non-specific error", \
+ "Interface already exists", \
+ "Interface not found", \
+ "Interface is still connected", \
+ "Out of memory", \
+ "Could not map domain memory" }
+
+/*
+ * CMSG_NETIF_BE_CREATE:
+ * When the driver sends a successful response then the interface is fully
+ * created. The controller will send a DOWN notification to the front-end
+ * driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Domain attached to new interface. */
+ u32 netif_handle; /* 4: Domain-specific interface handle. */
+ u8 mac[6]; /* 8 */
+ u16 __pad; /* 14 */
+ /* OUT */
+ u32 status; /* 16 */
+} PACKED netif_be_create_t; /* 20 bytes */
+
+/*
+ * CMSG_NETIF_BE_DESTROY:
+ * When the driver sends a successful response then the interface is fully
+ * torn down. The controller will send a DESTROYED notification to the
+ * front-end driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Identify interface to be destroyed. */
+ u32 netif_handle; /* 4: ...ditto... */
+ /* OUT */
+ u32 status; /* 8 */
+} PACKED netif_be_destroy_t; /* 12 bytes */
+
+/*
+ * CMSG_NETIF_BE_CONNECT:
+ * When the driver sends a successful response then the interface is fully
+ * connected. The controller will send a CONNECTED notification to the
+ * front-end driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Domain attached to new interface. */
+ u32 netif_handle; /* 4: Domain-specific interface handle. */
+ memory_t tx_shmem_frame; /* 8: Page cont. tx shared comms window. */
+ MEMORY_PADDING;
+ memory_t rx_shmem_frame; /* 16: Page cont. rx shared comms window. */
+ MEMORY_PADDING;
+ u16 evtchn; /* 24: Event channel for notifications. */
+ u16 __pad; /* 26 */
+ /* OUT */
+ u32 status; /* 28 */
+} PACKED netif_be_connect_t; /* 32 bytes */
+
+/*
+ * CMSG_NETIF_BE_DISCONNECT:
+ * When the driver sends a successful response then the interface is fully
+ * disconnected. The controller will send a DOWN notification to the front-end
+ * driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Domain attached to new interface. */
+ u32 netif_handle; /* 4: Domain-specific interface handle. */
+ /* OUT */
+ u32 status; /* 8 */
+} PACKED netif_be_disconnect_t; /* 12 bytes */
+
+/*
+ * CMSG_NETIF_BE_DRIVER_STATUS_CHANGED:
+ * Notify the domain controller that the back-end driver is DOWN or UP.
+ * If the driver goes DOWN while interfaces are still UP, the domain
+ * will automatically send DOWN notifications.
+ */
+typedef struct {
+ u32 status; /* 0: NETIF_DRIVER_STATUS_??? */
+} PACKED netif_be_driver_status_changed_t; /* 4 bytes */
+
+
+/******************************************************************************
+ * SHUTDOWN DEFINITIONS
+ */
+
+/*
+ * Subtypes for shutdown messages.
+ */
+#define CMSG_SHUTDOWN_POWEROFF 0 /* Clean shutdown (SHUTDOWN_poweroff). */
+#define CMSG_SHUTDOWN_REBOOT 1 /* Clean shutdown (SHUTDOWN_reboot). */
+#define CMSG_SHUTDOWN_SUSPEND 2 /* Create suspend info, then */
+ /* SHUTDOWN_suspend. */
+
+#endif /* __DOMAIN_CONTROLLER_H__ */
--- /dev/null
+/******************************************************************************
+ * utils.c
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#include <Python.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <sys/poll.h>
+#include <netinet/in.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <xc.h>
+
+#include <hypervisor-if.h>
+#include "domain_controller.h"
+
+#include <asm-xen/proc_cmd.h>
+
+#define XENPKG "xen.ext.xu"
+
+/* Needed for Python versions earlier than 2.3. */
+#ifndef PyMODINIT_FUNC
+#define PyMODINIT_FUNC DL_EXPORT(void)
+#endif
+
+/* NB. The following should be kept in sync with the kernel's evtchn driver. */
+#define EVTCHN_DEV_NAME "/dev/xen/evtchn"
+#define EVTCHN_DEV_MAJOR 10
+#define EVTCHN_DEV_MINOR 200
+#define PORT_NORMAL 0x0000 /* A standard event notification. */
+#define PORT_EXCEPTION 0x8000 /* An exceptional notification. */
+#define PORTIDX_MASK 0x7fff /* Strip subtype to obtain port index. */
+/* /dev/xen/evtchn ioctls: */
+/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */
+#define EVTCHN_RESET _IO('E', 1)
+/* EVTCHN_BIND: Bind to teh specified event-channel port. */
+#define EVTCHN_BIND _IO('E', 2)
+/* EVTCHN_UNBIND: Unbind from the specified event-channel port. */
+#define EVTCHN_UNBIND _IO('E', 3)
+
+/* Size of a machine page frame. */
+#define PAGE_SIZE 4096
+
+
+/*
+ * *********************** NOTIFIER ***********************
+ */
+
+typedef struct {
+ PyObject_HEAD;
+ int evtchn_fd;
+} xu_notifier_object;
+
+static PyObject *xu_notifier_read(PyObject *self, PyObject *args)
+{
+ xu_notifier_object *xun = (xu_notifier_object *)self;
+ u16 v;
+ int bytes;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ while ( (bytes = read(xun->evtchn_fd, &v, sizeof(v))) == -1 )
+ {
+ if ( errno == EINTR )
+ continue;
+ if ( errno == EAGAIN )
+ goto none;
+ return PyErr_SetFromErrno(PyExc_IOError);
+ }
+
+ if ( bytes == sizeof(v) )
+ return Py_BuildValue("(i,i)", v&PORTIDX_MASK, v&~PORTIDX_MASK);
+
+ none:
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *xu_notifier_unmask(PyObject *self, PyObject *args)
+{
+ xu_notifier_object *xun = (xu_notifier_object *)self;
+ u16 v;
+ int idx;
+
+ if ( !PyArg_ParseTuple(args, "i", &idx) )
+ return NULL;
+
+ v = (u16)idx;
+
+ (void)write(xun->evtchn_fd, &v, sizeof(v));
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *xu_notifier_bind(PyObject *self, PyObject *args)
+{
+ xu_notifier_object *xun = (xu_notifier_object *)self;
+ int idx;
+
+ if ( !PyArg_ParseTuple(args, "i", &idx) )
+ return NULL;
+
+ if ( ioctl(xun->evtchn_fd, EVTCHN_BIND, idx) != 0 )
+ return PyErr_SetFromErrno(PyExc_IOError);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *xu_notifier_unbind(PyObject *self, PyObject *args)
+{
+ xu_notifier_object *xun = (xu_notifier_object *)self;
+ int idx;
+
+ if ( !PyArg_ParseTuple(args, "i", &idx) )
+ return NULL;
+
+ if ( ioctl(xun->evtchn_fd, EVTCHN_UNBIND, idx) != 0 )
+ return PyErr_SetFromErrno(PyExc_IOError);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *xu_notifier_fileno(PyObject *self, PyObject *args)
+{
+ xu_notifier_object *xun = (xu_notifier_object *)self;
+ return PyInt_FromLong(xun->evtchn_fd);
+}
+
+static PyMethodDef xu_notifier_methods[] = {
+ { "read",
+ (PyCFunction)xu_notifier_read,
+ METH_VARARGS,
+ "Read a (@port, @type) pair.\n" },
+
+ { "unmask",
+ (PyCFunction)xu_notifier_unmask,
+ METH_VARARGS,
+ "Unmask notifications for a @port.\n" },
+
+ { "bind",
+ (PyCFunction)xu_notifier_bind,
+ METH_VARARGS,
+ "Get notifications for a @port.\n" },
+
+ { "unbind",
+ (PyCFunction)xu_notifier_unbind,
+ METH_VARARGS,
+ "No longer get notifications for a @port.\n" },
+
+ { "fileno",
+ (PyCFunction)xu_notifier_fileno,
+ METH_VARARGS,
+ "Return the file descriptor for the notification channel.\n" },
+
+ { NULL, NULL, 0, NULL }
+};
+
+staticforward PyTypeObject xu_notifier_type;
+
+static PyObject *xu_notifier_new(PyObject *self, PyObject *args)
+{
+ xu_notifier_object *xun;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ xun = PyObject_New(xu_notifier_object, &xu_notifier_type);
+
+ reopen:
+ xun->evtchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR);
+ if ( xun->evtchn_fd == -1 )
+ {
+ if ( (errno == ENOENT) &&
+ ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
+ (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600,
+ (EVTCHN_DEV_MAJOR << 8) | EVTCHN_DEV_MINOR) == 0) )
+ goto reopen;
+ PyObject_Del((PyObject *)xun);
+ return PyErr_SetFromErrno(PyExc_IOError);
+ }
+
+ return (PyObject *)xun;
+}
+
+static PyObject *xu_notifier_getattr(PyObject *obj, char *name)
+{
+ if ( strcmp(name, "EXCEPTION") == 0 )
+ return PyInt_FromLong(PORT_EXCEPTION);
+ if ( strcmp(name, "NORMAL") == 0 )
+ return PyInt_FromLong(PORT_NORMAL);
+ return Py_FindMethod(xu_notifier_methods, obj, name);
+}
+
+static void xu_notifier_dealloc(PyObject *self)
+{
+ xu_notifier_object *xun = (xu_notifier_object *)self;
+ (void)close(xun->evtchn_fd);
+ PyObject_Del(self);
+}
+
+static PyTypeObject xu_notifier_type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "notifier",
+ sizeof(xu_notifier_object),
+ 0,
+ xu_notifier_dealloc, /* tp_dealloc */
+ NULL, /* tp_print */
+ xu_notifier_getattr, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+ NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ NULL /* tp_hash */
+};
+
+
+
+/*
+ * *********************** MESSAGE ***********************
+ */
+
+#define TYPE(_x,_y) (((_x)<<8)|(_y))
+#define P2C(_struct, _field, _ctype) \
+ do { \
+ PyObject *obj; \
+ if ( (obj = PyDict_GetItemString(payload, #_field)) != NULL ) \
+ { \
+ if ( PyInt_Check(obj) ) \
+ { \
+ ((_struct *)&xum->msg.msg[0])->_field = \
+ (_ctype)PyInt_AsLong(obj); \
+ dict_items_parsed++; \
+ } \
+ else if ( PyLong_Check(obj) ) \
+ { \
+ ((_struct *)&xum->msg.msg[0])->_field = \
+ (_ctype)PyLong_AsUnsignedLongLong(obj); \
+ dict_items_parsed++; \
+ } \
+ } \
+ xum->msg.length = sizeof(_struct); \
+ } while ( 0 )
+#define C2P(_struct, _field, _pytype, _ctype) \
+ do { \
+ PyObject *obj = Py ## _pytype ## _From ## _ctype \
+ (((_struct *)&xum->msg.msg[0])->_field); \
+ if ( dict == NULL ) dict = PyDict_New(); \
+ PyDict_SetItemString(dict, #_field, obj); \
+ } while ( 0 )
+
+typedef struct {
+ PyObject_HEAD;
+ control_msg_t msg;
+} xu_message_object;
+
+static PyObject *xu_message_append_payload(PyObject *self, PyObject *args)
+{
+ xu_message_object *xum = (xu_message_object *)self;
+ char *str;
+ int len;
+
+ if ( !PyArg_ParseTuple(args, "s#", &str, &len) )
+ return NULL;
+
+ if ( (len + xum->msg.length) > sizeof(xum->msg.msg) )
+ {
+ PyErr_SetString(PyExc_RuntimeError, "out of space in control message");
+ return NULL;
+ }
+
+ memcpy(&xum->msg.msg[xum->msg.length], str, len);
+ xum->msg.length += len;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *xu_message_set_response_fields(PyObject *self, PyObject *args)
+{
+ xu_message_object *xum = (xu_message_object *)self;
+ PyObject *payload;
+ int dict_items_parsed = 0;
+
+ if ( !PyArg_ParseTuple(args, "O", &payload) )
+ return NULL;
+
+ if ( !PyDict_Check(payload) )
+ {
+ PyErr_SetString(PyExc_TypeError, "payload is not a dictionary");
+ return NULL;
+ }
+
+ switch ( TYPE(xum->msg.type, xum->msg.subtype) )
+ {
+ case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED):
+ P2C(blkif_fe_driver_status_changed_t, nr_interfaces, u32);
+ break;
+ case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED):
+ P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32);
+ break;
+ }
+
+ if ( dict_items_parsed != PyDict_Size(payload) )
+ {
+ PyErr_SetString(PyExc_TypeError, "payload contains bad items");
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *xu_message_get_payload(PyObject *self, PyObject *args)
+{
+ xu_message_object *xum = (xu_message_object *)self;
+ PyObject *dict = NULL;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ switch ( TYPE(xum->msg.type, xum->msg.subtype) )
+ {
+ case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED):
+ C2P(blkif_fe_interface_status_changed_t, handle, Int, Long);
+ C2P(blkif_fe_interface_status_changed_t, status, Int, Long);
+ C2P(blkif_fe_interface_status_changed_t, evtchn, Int, Long);
+ return dict;
+ case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED):
+ C2P(blkif_fe_driver_status_changed_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT):
+ C2P(blkif_fe_interface_connect_t, handle, Int, Long);
+ C2P(blkif_fe_interface_connect_t, shmem_frame, Int, Long);
+ return dict;
+ case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_DISCONNECT):
+ C2P(blkif_fe_interface_disconnect_t, handle, Int, Long);
+ return dict;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE):
+ C2P(blkif_be_create_t, domid, Int, Long);
+ C2P(blkif_be_create_t, blkif_handle, Int, Long);
+ C2P(blkif_be_create_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY):
+ C2P(blkif_be_destroy_t, domid, Int, Long);
+ C2P(blkif_be_destroy_t, blkif_handle, Int, Long);
+ C2P(blkif_be_destroy_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT):
+ C2P(blkif_be_connect_t, domid, Int, Long);
+ C2P(blkif_be_connect_t, blkif_handle, Int, Long);
+ C2P(blkif_be_connect_t, shmem_frame, Int, Long);
+ C2P(blkif_be_connect_t, evtchn, Int, Long);
+ C2P(blkif_be_connect_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT):
+ C2P(blkif_be_disconnect_t, domid, Int, Long);
+ C2P(blkif_be_disconnect_t, blkif_handle, Int, Long);
+ C2P(blkif_be_disconnect_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE):
+ C2P(blkif_be_vbd_create_t, domid, Int, Long);
+ C2P(blkif_be_vbd_create_t, blkif_handle, Int, Long);
+ C2P(blkif_be_vbd_create_t, vdevice, Int, Long);
+ C2P(blkif_be_vbd_create_t, readonly, Int, Long);
+ C2P(blkif_be_vbd_create_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY):
+ C2P(blkif_be_vbd_destroy_t, domid, Int, Long);
+ C2P(blkif_be_vbd_destroy_t, blkif_handle, Int, Long);
+ C2P(blkif_be_vbd_destroy_t, vdevice, Int, Long);
+ C2P(blkif_be_vbd_destroy_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW):
+ C2P(blkif_be_vbd_grow_t, domid, Int, Long);
+ C2P(blkif_be_vbd_grow_t, blkif_handle, Int, Long);
+ C2P(blkif_be_vbd_grow_t, vdevice, Int, Long);
+ C2P(blkif_be_vbd_grow_t, extent.sector_start,
+ Long, UnsignedLongLong);
+ C2P(blkif_be_vbd_grow_t, extent.sector_length,
+ Long, UnsignedLongLong);
+ C2P(blkif_be_vbd_grow_t, extent.device, Int, Long);
+ C2P(blkif_be_vbd_grow_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_SHRINK):
+ C2P(blkif_be_vbd_shrink_t, domid, Int, Long);
+ C2P(blkif_be_vbd_shrink_t, blkif_handle, Int, Long);
+ C2P(blkif_be_vbd_shrink_t, vdevice, Int, Long);
+ C2P(blkif_be_vbd_shrink_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED):
+ C2P(blkif_be_driver_status_changed_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED):
+ C2P(netif_fe_interface_status_changed_t, handle, Int, Long);
+ C2P(netif_fe_interface_status_changed_t, status, Int, Long);
+ C2P(netif_fe_interface_status_changed_t, evtchn, Int, Long);
+ return dict;
+ case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED):
+ C2P(netif_fe_driver_status_changed_t, status, Int, Long);
+ C2P(netif_fe_driver_status_changed_t, nr_interfaces, Int, Long);
+ return dict;
+ case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT):
+ C2P(netif_fe_interface_connect_t, handle, Int, Long);
+ C2P(netif_fe_interface_connect_t, tx_shmem_frame, Int, Long);
+ C2P(netif_fe_interface_connect_t, rx_shmem_frame, Int, Long);
+ return dict;
+ case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_DISCONNECT):
+ C2P(netif_fe_interface_disconnect_t, handle, Int, Long);
+ return dict;
+ case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE):
+ C2P(netif_be_create_t, domid, Int, Long);
+ C2P(netif_be_create_t, netif_handle, Int, Long);
+ C2P(netif_be_create_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY):
+ C2P(netif_be_destroy_t, domid, Int, Long);
+ C2P(netif_be_destroy_t, netif_handle, Int, Long);
+ C2P(netif_be_destroy_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT):
+ C2P(netif_be_connect_t, domid, Int, Long);
+ C2P(netif_be_connect_t, netif_handle, Int, Long);
+ C2P(netif_be_connect_t, tx_shmem_frame, Int, Long);
+ C2P(netif_be_connect_t, rx_shmem_frame, Int, Long);
+ C2P(netif_be_connect_t, evtchn, Int, Long);
+ C2P(netif_be_connect_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT):
+ C2P(netif_be_disconnect_t, domid, Int, Long);
+ C2P(netif_be_disconnect_t, netif_handle, Int, Long);
+ C2P(netif_be_disconnect_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED):
+ C2P(netif_be_driver_status_changed_t, status, Int, Long);
+ return dict;
+ }
+
+ return PyString_FromStringAndSize(xum->msg.msg, xum->msg.length);
+}
+
+static PyObject *xu_message_get_header(PyObject *self, PyObject *args)
+{
+ xu_message_object *xum = (xu_message_object *)self;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ return Py_BuildValue("{s:i,s:i,s:i}",
+ "type", xum->msg.type,
+ "subtype", xum->msg.subtype,
+ "id", xum->msg.id);
+}
+
+static PyMethodDef xu_message_methods[] = {
+ { "append_payload",
+ (PyCFunction)xu_message_append_payload,
+ METH_VARARGS,
+ "Append @str to the message payload.\n" },
+
+ { "set_response_fields",
+ (PyCFunction)xu_message_set_response_fields,
+ METH_VARARGS,
+ "Fill in the response fields in a message that was passed to us.\n" },
+
+ { "get_payload",
+ (PyCFunction)xu_message_get_payload,
+ METH_VARARGS,
+ "Return the message payload in string form.\n" },
+
+ { "get_header",
+ (PyCFunction)xu_message_get_header,
+ METH_VARARGS,
+ "Returns a dictionary of values for @type, @subtype, and @id.\n" },
+
+ { NULL, NULL, 0, NULL }
+};
+
+staticforward PyTypeObject xu_message_type;
+
+static PyObject *xu_message_new(PyObject *self, PyObject *args)
+{
+ xu_message_object *xum;
+ int type, subtype, id, dict_items_parsed = 0;
+ PyObject *payload = NULL;
+
+ if ( !PyArg_ParseTuple(args, "iii|O", &type, &subtype, &id, &payload) )
+ return NULL;
+
+ xum = PyObject_New(xu_message_object, &xu_message_type);
+
+ xum->msg.type = type;
+ xum->msg.subtype = subtype;
+ xum->msg.id = id;
+ xum->msg.length = 0;
+
+ if ( payload == NULL )
+ return (PyObject *)xum;
+
+ if ( !PyDict_Check(payload) )
+ {
+ PyErr_SetString(PyExc_TypeError, "payload is not a dictionary");
+ PyObject_Del((PyObject *)xum);
+ return NULL;
+ }
+
+ switch ( TYPE(type, subtype) )
+ {
+ case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED):
+ P2C(blkif_fe_interface_status_changed_t, handle, u32);
+ P2C(blkif_fe_interface_status_changed_t, status, u32);
+ P2C(blkif_fe_interface_status_changed_t, evtchn, u16);
+ break;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE):
+ P2C(blkif_be_create_t, domid, u32);
+ P2C(blkif_be_create_t, blkif_handle, u32);
+ break;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY):
+ P2C(blkif_be_destroy_t, domid, u32);
+ P2C(blkif_be_destroy_t, blkif_handle, u32);
+ break;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT):
+ P2C(blkif_be_connect_t, domid, u32);
+ P2C(blkif_be_connect_t, blkif_handle, u32);
+ P2C(blkif_be_connect_t, shmem_frame, memory_t);
+ P2C(blkif_be_connect_t, evtchn, u16);
+ break;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT):
+ P2C(blkif_be_disconnect_t, domid, u32);
+ P2C(blkif_be_disconnect_t, blkif_handle, u32);
+ break;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE):
+ P2C(blkif_be_vbd_create_t, domid, u32);
+ P2C(blkif_be_vbd_create_t, blkif_handle, u32);
+ P2C(blkif_be_vbd_create_t, vdevice, blkif_vdev_t);
+ P2C(blkif_be_vbd_create_t, readonly, u16);
+ break;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY):
+ P2C(blkif_be_vbd_destroy_t, domid, u32);
+ P2C(blkif_be_vbd_destroy_t, blkif_handle, u32);
+ P2C(blkif_be_vbd_destroy_t, vdevice, blkif_vdev_t);
+ break;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW):
+ P2C(blkif_be_vbd_grow_t, domid, u32);
+ P2C(blkif_be_vbd_grow_t, blkif_handle, u32);
+ P2C(blkif_be_vbd_grow_t, vdevice, blkif_vdev_t);
+ P2C(blkif_be_vbd_grow_t, extent.sector_start, blkif_sector_t);
+ P2C(blkif_be_vbd_grow_t, extent.sector_length, blkif_sector_t);
+ P2C(blkif_be_vbd_grow_t, extent.device, blkif_pdev_t);
+ break;
+ case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_SHRINK):
+ P2C(blkif_be_vbd_shrink_t, domid, u32);
+ P2C(blkif_be_vbd_shrink_t, blkif_handle, u32);
+ P2C(blkif_be_vbd_shrink_t, vdevice, blkif_vdev_t);
+ break;
+ case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED):
+ P2C(netif_fe_interface_status_changed_t, handle, u32);
+ P2C(netif_fe_interface_status_changed_t, status, u32);
+ P2C(netif_fe_interface_status_changed_t, evtchn, u16);
+ P2C(netif_fe_interface_status_changed_t, mac[0], u8);
+ P2C(netif_fe_interface_status_changed_t, mac[1], u8);
+ P2C(netif_fe_interface_status_changed_t, mac[2], u8);
+ P2C(netif_fe_interface_status_changed_t, mac[3], u8);
+ P2C(netif_fe_interface_status_changed_t, mac[4], u8);
+ P2C(netif_fe_interface_status_changed_t, mac[5], u8);
+ break;
+ case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE):
+ P2C(netif_be_create_t, domid, u32);
+ P2C(netif_be_create_t, netif_handle, u32);
+ P2C(netif_be_create_t, mac[0], u8);
+ P2C(netif_be_create_t, mac[1], u8);
+ P2C(netif_be_create_t, mac[2], u8);
+ P2C(netif_be_create_t, mac[3], u8);
+ P2C(netif_be_create_t, mac[4], u8);
+ P2C(netif_be_create_t, mac[5], u8);
+ break;
+ case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY):
+ P2C(netif_be_destroy_t, domid, u32);
+ P2C(netif_be_destroy_t, netif_handle, u32);
+ break;
+ case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT):
+ P2C(netif_be_connect_t, domid, u32);
+ P2C(netif_be_connect_t, netif_handle, u32);
+ P2C(netif_be_connect_t, tx_shmem_frame, memory_t);
+ P2C(netif_be_connect_t, rx_shmem_frame, memory_t);
+ P2C(netif_be_connect_t, evtchn, u16);
+ break;
+ case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT):
+ P2C(netif_be_disconnect_t, domid, u32);
+ P2C(netif_be_disconnect_t, netif_handle, u32);
+ break;
+ case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED):
+ P2C(netif_fe_driver_status_changed_t, status, u32);
+ P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32);
+ break;
+ }
+
+ if ( dict_items_parsed != PyDict_Size(payload) )
+ {
+ PyErr_SetString(PyExc_TypeError, "payload contains bad items");
+ PyObject_Del((PyObject *)xum);
+ return NULL;
+ }
+
+ return (PyObject *)xum;
+}
+
+static PyObject *xu_message_getattr(PyObject *obj, char *name)
+{
+ xu_message_object *xum;
+ if ( strcmp(name, "MAX_PAYLOAD") == 0 )
+ return PyInt_FromLong(sizeof(xum->msg.msg));
+ return Py_FindMethod(xu_message_methods, obj, name);
+}
+
+static void xu_message_dealloc(PyObject *self)
+{
+ PyObject_Del(self);
+}
+
+static PyTypeObject xu_message_type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "message",
+ sizeof(xu_message_object),
+ 0,
+ xu_message_dealloc, /* tp_dealloc */
+ NULL, /* tp_print */
+ xu_message_getattr, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+ NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ NULL /* tp_hash */
+};
+
+
+
+/*
+ * *********************** PORT ***********************
+ */
+
+static control_if_t *map_control_interface(int fd, unsigned long pfn)
+{
+ char *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE,
+ MAP_SHARED, fd, pfn * PAGE_SIZE);
+ if ( vaddr == MAP_FAILED )
+ return NULL;
+ return (control_if_t *)(vaddr + 2048);
+}
+static void unmap_control_interface(int fd, control_if_t *c)
+{
+ char *vaddr = (char *)c - 2048;
+ (void)munmap(vaddr, PAGE_SIZE);
+}
+
+typedef struct xu_port_object {
+ PyObject_HEAD;
+ int mem_fd;
+ int xc_handle;
+ u32 remote_dom;
+ int local_port, remote_port;
+ control_if_t *interface;
+ CONTROL_RING_IDX tx_req_cons, tx_resp_prod;
+ CONTROL_RING_IDX rx_req_prod, rx_resp_cons;
+} xu_port_object;
+
+static PyObject *port_error;
+
+static int xup_connect(xu_port_object *xup, domid_t dom,
+ int local_port, int remote_port){
+ // From our prespective rx = producer, tx = consumer.
+ int err = 0;
+ printf("%s> dom=%u %d:%d\n", __FUNCTION__, (unsigned int)dom,
+ local_port, remote_port);
+
+ // Consumer = tx.
+ //xup->interface->tx_resp_prod = 0;
+ //xup->interface->tx_req_prod = 0;
+ xup->tx_resp_prod = xup->interface->tx_resp_prod;
+ xup->tx_req_cons = xup->interface->tx_resp_prod;
+ printf("%s> tx: %u %u : %u %u\n", __FUNCTION__,
+ (unsigned int)xup->interface->tx_resp_prod,
+ (unsigned int)xup->tx_resp_prod,
+ (unsigned int)xup->tx_req_cons,
+ (unsigned int)xup->interface->tx_req_prod);
+
+ // Producer = rx.
+ //xup->interface->rx_req_prod = 0;
+ //xup->interface->rx_resp_prod = 0;
+ xup->rx_req_prod = xup->interface->rx_req_prod;
+ xup->rx_resp_cons = xup->interface->rx_resp_prod;
+ printf("%s> rx: %u %u : %u %u\n", __FUNCTION__,
+ (unsigned int)xup->rx_resp_cons,
+ (unsigned int)xup->interface->rx_resp_prod,
+ (unsigned int)xup->interface->rx_req_prod,
+ (unsigned int)xup->rx_req_prod);
+
+ xup->remote_dom = dom;
+ xup->local_port = local_port;
+ xup->remote_port = remote_port;
+
+ printf("%s< err=%d\n", __FUNCTION__, err);
+ return err;
+}
+
+static PyObject *xu_port_notify(PyObject *self, PyObject *args)
+{
+ xu_port_object *xup = (xu_port_object *)self;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ (void)xc_evtchn_send(xup->xc_handle, xup->local_port);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *xu_port_read_request(PyObject *self, PyObject *args)
+{
+ xu_port_object *xup = (xu_port_object *)self;
+ xu_message_object *xum;
+ CONTROL_RING_IDX c = xup->tx_req_cons;
+ control_if_t *cif = xup->interface;
+ control_msg_t *cmsg;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ if ( (c == cif->tx_req_prod) ||
+ ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) )
+ {
+ PyErr_SetString(port_error, "no request to read");
+ return NULL;
+ }
+
+ cmsg = &cif->tx_ring[MASK_CONTROL_IDX(c)];
+ xum = PyObject_New(xu_message_object, &xu_message_type);
+ memcpy(&xum->msg, cmsg, sizeof(*cmsg));
+ if ( xum->msg.length > sizeof(xum->msg.msg) )
+ xum->msg.length = sizeof(xum->msg.msg);
+ xup->tx_req_cons++;
+ return (PyObject *)xum;
+}
+
+static PyObject *xu_port_write_request(PyObject *self, PyObject *args)
+{
+ xu_port_object *xup = (xu_port_object *)self;
+ xu_message_object *xum;
+ CONTROL_RING_IDX p = xup->rx_req_prod;
+ control_if_t *cif = xup->interface;
+ control_msg_t *cmsg;
+
+ if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) )
+ return NULL;
+
+ if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) )
+ {
+ PyErr_SetString(PyExc_TypeError, "expected a " XENPKG ".message");
+ return NULL;
+ }
+
+ if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) )
+ {
+ PyErr_SetString(port_error, "no space to write request");
+ return NULL;
+ }
+
+ cmsg = &cif->rx_ring[MASK_CONTROL_IDX(p)];
+ memcpy(cmsg, &xum->msg, sizeof(*cmsg));
+
+ xup->rx_req_prod = cif->rx_req_prod = p + 1;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *xu_port_read_response(PyObject *self, PyObject *args)
+{
+ xu_port_object *xup = (xu_port_object *)self;
+ xu_message_object *xum;
+ CONTROL_RING_IDX c = xup->rx_resp_cons;
+ control_if_t *cif = xup->interface;
+ control_msg_t *cmsg;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) )
+ {
+ PyErr_SetString(port_error, "no response to read");
+ return NULL;
+ }
+
+ cmsg = &cif->rx_ring[MASK_CONTROL_IDX(c)];
+ xum = PyObject_New(xu_message_object, &xu_message_type);
+ memcpy(&xum->msg, cmsg, sizeof(*cmsg));
+ if ( xum->msg.length > sizeof(xum->msg.msg) )
+ xum->msg.length = sizeof(xum->msg.msg);
+ xup->rx_resp_cons++;
+ return (PyObject *)xum;
+}
+
+static PyObject *xu_port_write_response(PyObject *self, PyObject *args)
+{
+ xu_port_object *xup = (xu_port_object *)self;
+ xu_message_object *xum;
+ CONTROL_RING_IDX p = xup->tx_resp_prod;
+ control_if_t *cif = xup->interface;
+ control_msg_t *cmsg;
+
+ if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) )
+ return NULL;
+
+ if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) )
+ {
+ PyErr_SetString(PyExc_TypeError, "expected a " XENPKG ".message");
+ return NULL;
+ }
+
+ if ( p == xup->tx_req_cons )
+ {
+ PyErr_SetString(port_error, "no space to write response");
+ return NULL;
+ }
+
+ cmsg = &cif->tx_ring[MASK_CONTROL_IDX(p)];
+ memcpy(cmsg, &xum->msg, sizeof(*cmsg));
+
+ xup->tx_resp_prod = cif->tx_resp_prod = p + 1;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *xu_port_request_to_read(PyObject *self, PyObject *args)
+{
+ xu_port_object *xup = (xu_port_object *)self;
+ CONTROL_RING_IDX c = xup->tx_req_cons;
+ control_if_t *cif = xup->interface;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ if ( (c == cif->tx_req_prod) ||
+ ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) )
+ return PyInt_FromLong(0);
+
+ return PyInt_FromLong(1);
+}
+
+static PyObject *xu_port_space_to_write_request(PyObject *self, PyObject *args)
+{
+ xu_port_object *xup = (xu_port_object *)self;
+ CONTROL_RING_IDX p = xup->rx_req_prod;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) )
+ return PyInt_FromLong(0);
+
+ return PyInt_FromLong(1);
+}
+
+static PyObject *xu_port_response_to_read(PyObject *self, PyObject *args)
+{
+ xu_port_object *xup = (xu_port_object *)self;
+ CONTROL_RING_IDX c = xup->rx_resp_cons;
+ control_if_t *cif = xup->interface;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) )
+ return PyInt_FromLong(0);
+
+ return PyInt_FromLong(1);
+}
+
+static PyObject *xu_port_space_to_write_response(
+ PyObject *self, PyObject *args)
+{
+ xu_port_object *xup = (xu_port_object *)self;
+ CONTROL_RING_IDX p = xup->tx_resp_prod;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ if ( p == xup->tx_req_cons )
+ return PyInt_FromLong(0);
+
+ return PyInt_FromLong(1);
+}
+
+static PyMethodDef xu_port_methods[] = {
+ { "notify",
+ (PyCFunction)xu_port_notify,
+ METH_VARARGS,
+ "Send a notification to the remote end.\n" },
+
+ { "read_request",
+ (PyCFunction)xu_port_read_request,
+ METH_VARARGS,
+ "Read a request message from the control interface.\n" },
+
+ { "write_request",
+ (PyCFunction)xu_port_write_request,
+ METH_VARARGS,
+ "Write a request message to the control interface.\n" },
+
+ { "read_response",
+ (PyCFunction)xu_port_read_response,
+ METH_VARARGS,
+ "Read a response message from the control interface.\n" },
+
+ { "write_response",
+ (PyCFunction)xu_port_write_response,
+ METH_VARARGS,
+ "Write a response message to the control interface.\n" },
+
+ { "request_to_read",
+ (PyCFunction)xu_port_request_to_read,
+ METH_VARARGS,
+ "Returns TRUE if there is a request message to read.\n" },
+
+ { "space_to_write_request",
+ (PyCFunction)xu_port_space_to_write_request,
+ METH_VARARGS,
+ "Returns TRUE if there is space to write a request message.\n" },
+
+ { "response_to_read",
+ (PyCFunction)xu_port_response_to_read,
+ METH_VARARGS,
+ "Returns TRUE if there is a response message to read.\n" },
+
+ { "space_to_write_response",
+ (PyCFunction)xu_port_space_to_write_response,
+ METH_VARARGS,
+ "Returns TRUE if there is space to write a response message.\n" },
+
+ { NULL, NULL, 0, NULL }
+};
+
+staticforward PyTypeObject xu_port_type;
+
+static PyObject *xu_port_new(PyObject *self, PyObject *args)
+{
+ xu_port_object *xup;
+ u32 dom;
+ int port1, port2;
+ xc_dominfo_t info;
+
+ if ( !PyArg_ParseTuple(args, "i", &dom) )
+ return NULL;
+
+ xup = PyObject_New(xu_port_object, &xu_port_type);
+
+ if ( (xup->mem_fd = open("/dev/mem", O_RDWR)) == -1 )
+ {
+ PyErr_SetString(port_error, "Could not open '/dev/mem'");
+ goto fail1;
+ }
+
+ /* Set the General-Purpose Subject whose page frame will be mapped. */
+ (void)ioctl(xup->mem_fd, _IO('M', 1), (unsigned long)dom);
+
+ if ( (xup->xc_handle = xc_interface_open()) == -1 )
+ {
+ PyErr_SetString(port_error, "Could not open Xen control interface");
+ goto fail2;
+ }
+
+ if ( dom == 0 )
+ {
+ /*
+ * The control-interface event channel for DOM0 is already set up.
+ * We use an ioctl to discover the port at our end of the channel.
+ */
+ port1 = ioctl(xup->xc_handle, IOCTL_PRIVCMD_INITDOMAIN_EVTCHN, NULL);
+ port2 = -1; /* We don't need the remote end of the DOM0 link. */
+ if ( port1 < 0 )
+ {
+ PyErr_SetString(port_error, "Could not open channel to DOM0");
+ goto fail3;
+ }
+ }
+ else if ( xc_evtchn_bind_interdomain(xup->xc_handle,
+ DOMID_SELF, dom,
+ &port1, &port2) != 0 )
+ {
+ PyErr_SetString(port_error, "Could not open channel to domain");
+ goto fail3;
+ }
+
+ if ( (xc_domain_getinfo(xup->xc_handle, dom, 1, &info) != 1) ||
+ (info.domid != dom) )
+ {
+ PyErr_SetString(port_error, "Failed to obtain domain status");
+ goto fail4;
+ }
+
+ xup->interface =
+ map_control_interface(xup->mem_fd, info.shared_info_frame);
+ if ( xup->interface == NULL )
+ {
+ PyErr_SetString(port_error, "Failed to map domain control interface");
+ goto fail4;
+ }
+
+ xup_connect(xup, dom, port1, port2);
+ return (PyObject *)xup;
+
+
+ fail4:
+ (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, port1);
+ fail3:
+ (void)xc_interface_close(xup->xc_handle);
+ fail2:
+ (void)close(xup->mem_fd);
+ fail1:
+ PyObject_Del((PyObject *)xup);
+ return NULL;
+}
+
+static PyObject *xu_port_getattr(PyObject *obj, char *name)
+{
+ xu_port_object *xup = (xu_port_object *)obj;
+ if ( strcmp(name, "local_port") == 0 )
+ return PyInt_FromLong(xup->local_port);
+ if ( strcmp(name, "remote_port") == 0 )
+ return PyInt_FromLong(xup->remote_port);
+ if ( strcmp(name, "remote_dom") == 0 )
+ return PyInt_FromLong(xup->remote_dom);
+ return Py_FindMethod(xu_port_methods, obj, name);
+}
+
+static void xu_port_dealloc(PyObject *self)
+{
+ xu_port_object *xup = (xu_port_object *)self;
+ unmap_control_interface(xup->mem_fd, xup->interface);
+ if ( xup->remote_dom != 0 )
+ (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, xup->local_port);
+ (void)xc_interface_close(xup->xc_handle);
+ (void)close(xup->mem_fd);
+ PyObject_Del(self);
+}
+
+static PyTypeObject xu_port_type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "port",
+ sizeof(xu_port_object),
+ 0,
+ xu_port_dealloc, /* tp_dealloc */
+ NULL, /* tp_print */
+ xu_port_getattr, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+ NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ NULL /* tp_hash */
+};
+
+
+
+/*
+ * *********************** BUFFER ***********************
+ */
+
+#define BUFSZ 65536
+#define MASK_BUF_IDX(_i) ((_i)&(BUFSZ-1))
+typedef unsigned int BUF_IDX;
+
+typedef struct {
+ PyObject_HEAD;
+ char *buf;
+ unsigned int prod, cons;
+} xu_buffer_object;
+
+static PyObject *__xu_buffer_peek(xu_buffer_object *xub, int max)
+{
+ PyObject *str1, *str2;
+ int len1, len2, c = MASK_BUF_IDX(xub->cons);
+
+ len1 = xub->prod - xub->cons;
+ if ( len1 > (BUFSZ - c) ) /* clip to ring wrap */
+ len1 = BUFSZ - c;
+ if ( len1 > max ) /* clip to specified maximum */
+ len1 = max;
+ if ( len1 < 0 ) /* sanity */
+ len1 = 0;
+
+ if ( (str1 = PyString_FromStringAndSize(&xub->buf[c], len1)) == NULL )
+ return NULL;
+
+ if ( (len1 < (xub->prod - xub->cons)) && (len1 < max) )
+ {
+ len2 = max - len1;
+ if ( len2 > MASK_BUF_IDX(xub->prod) )
+ len2 = MASK_BUF_IDX(xub->prod);
+ if ( len2 > 0 )
+ {
+ str2 = PyString_FromStringAndSize(&xub->buf[0], len2);
+ if ( str2 == NULL )
+ return NULL;
+ PyString_ConcatAndDel(&str1, str2);
+ if ( str1 == NULL )
+ return NULL;
+ }
+ }
+
+ return str1;
+}
+
+static PyObject *xu_buffer_peek(PyObject *self, PyObject *args)
+{
+ xu_buffer_object *xub = (xu_buffer_object *)self;
+ int max = 1024;
+
+ if ( !PyArg_ParseTuple(args, "|i", &max) )
+ return NULL;
+
+ return __xu_buffer_peek(xub, max);
+}
+
+static PyObject *xu_buffer_read(PyObject *self, PyObject *args)
+{
+ xu_buffer_object *xub = (xu_buffer_object *)self;
+ PyObject *str;
+ int max = 1024;
+
+ if ( !PyArg_ParseTuple(args, "|i", &max) )
+ return NULL;
+
+ if ( (str = __xu_buffer_peek(xub, max)) != NULL )
+ xub->cons += PyString_Size(str);
+
+ return str;
+}
+
+static PyObject *xu_buffer_discard(PyObject *self, PyObject *args)
+{
+ xu_buffer_object *xub = (xu_buffer_object *)self;
+ int max, len;
+
+ if ( !PyArg_ParseTuple(args, "i", &max) )
+ return NULL;
+
+ len = xub->prod - xub->cons;
+ if ( len > max )
+ len = max;
+ if ( len < 0 )
+ len = 0;
+
+ xub->cons += len;
+
+ return PyInt_FromLong(len);
+}
+
+static PyObject *xu_buffer_write(PyObject *self, PyObject *args)
+{
+ xu_buffer_object *xub = (xu_buffer_object *)self;
+ char *str;
+ int len, len1, len2;
+
+ if ( !PyArg_ParseTuple(args, "s#", &str, &len) )
+ return NULL;
+
+ len1 = len;
+ if ( len1 > (BUFSZ - MASK_BUF_IDX(xub->prod)) )
+ len1 = BUFSZ - MASK_BUF_IDX(xub->prod);
+ if ( len1 > (BUFSZ - (xub->prod - xub->cons)) )
+ len1 = BUFSZ - (xub->prod - xub->cons);
+
+ if ( len1 == 0 )
+ return PyInt_FromLong(0);
+
+ memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[0], len1);
+ xub->prod += len1;
+
+ if ( len1 < len )
+ {
+ len2 = len - len1;
+ if ( len2 > (BUFSZ - MASK_BUF_IDX(xub->prod)) )
+ len2 = BUFSZ - MASK_BUF_IDX(xub->prod);
+ if ( len2 > (BUFSZ - (xub->prod - xub->cons)) )
+ len2 = BUFSZ - (xub->prod - xub->cons);
+ if ( len2 != 0 )
+ {
+ memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[len1], len2);
+ xub->prod += len2;
+ return PyInt_FromLong(len1 + len2);
+ }
+ }
+
+ return PyInt_FromLong(len1);
+}
+
+static PyObject *xu_buffer_empty(PyObject *self, PyObject *args)
+{
+ xu_buffer_object *xub = (xu_buffer_object *)self;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ if ( xub->cons == xub->prod )
+ return PyInt_FromLong(1);
+
+ return PyInt_FromLong(0);
+}
+
+static PyObject *xu_buffer_full(PyObject *self, PyObject *args)
+{
+ xu_buffer_object *xub = (xu_buffer_object *)self;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ if ( (xub->prod - xub->cons) == BUFSZ )
+ return PyInt_FromLong(1);
+
+ return PyInt_FromLong(0);
+}
+
+static PyMethodDef xu_buffer_methods[] = {
+ { "peek",
+ (PyCFunction)xu_buffer_peek,
+ METH_VARARGS,
+ "Peek up to @max bytes from the buffer. Returns a string.\n" },
+
+ { "read",
+ (PyCFunction)xu_buffer_read,
+ METH_VARARGS,
+ "Read up to @max bytes from the buffer. Returns a string.\n" },
+
+ { "discard",
+ (PyCFunction)xu_buffer_discard,
+ METH_VARARGS,
+ "Discard up to @max bytes from the buffer. Returns number of bytes.\n" },
+
+ { "write",
+ (PyCFunction)xu_buffer_write,
+ METH_VARARGS,
+ "Write @string into buffer. Return number of bytes written.\n" },
+
+ { "empty",
+ (PyCFunction)xu_buffer_empty,
+ METH_VARARGS,
+ "Return TRUE if the buffer is empty.\n" },
+
+ { "full",
+ (PyCFunction)xu_buffer_full,
+ METH_VARARGS,
+ "Return TRUE if the buffer is full.\n" },
+
+ { NULL, NULL, 0, NULL }
+};
+
+staticforward PyTypeObject xu_buffer_type;
+
+static PyObject *xu_buffer_new(PyObject *self, PyObject *args)
+{
+ xu_buffer_object *xub;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ xub = PyObject_New(xu_buffer_object, &xu_buffer_type);
+
+ if ( (xub->buf = malloc(BUFSZ)) == NULL )
+ {
+ PyObject_Del((PyObject *)xub);
+ return NULL;
+ }
+
+ xub->prod = xub->cons = 0;
+
+ return (PyObject *)xub;
+}
+
+static PyObject *xu_buffer_getattr(PyObject *obj, char *name)
+{
+ return Py_FindMethod(xu_buffer_methods, obj, name);
+}
+
+static void xu_buffer_dealloc(PyObject *self)
+{
+ xu_buffer_object *xub = (xu_buffer_object *)self;
+ free(xub->buf);
+ PyObject_Del(self);
+}
+
+static PyTypeObject xu_buffer_type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "buffer",
+ sizeof(xu_buffer_object),
+ 0,
+ xu_buffer_dealloc, /* tp_dealloc */
+ NULL, /* tp_print */
+ xu_buffer_getattr, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+ NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ NULL /* tp_hash */
+};
+
+
+
+/*
+ * *********************** MODULE WRAPPER ***********************
+ */
+
+static void handle_child_death(int dummy)
+{
+ while ( waitpid(-1, NULL, WNOHANG) > 0 )
+ continue;
+}
+
+static PyObject *xu_autoreap(PyObject *self, PyObject *args)
+{
+ struct sigaction sa;
+
+ if ( !PyArg_ParseTuple(args, "") )
+ return NULL;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = handle_child_death;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
+ (void)sigaction(SIGCHLD, &sa, NULL);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMethodDef xu_methods[] = {
+ { "notifier", xu_notifier_new, METH_VARARGS,
+ "Create a new notifier." },
+ { "message", xu_message_new, METH_VARARGS,
+ "Create a new communications message." },
+ { "port", xu_port_new, METH_VARARGS,
+ "Create a new communications port." },
+ { "buffer", xu_buffer_new, METH_VARARGS,
+ "Create a new ring buffer." },
+ { "autoreap", xu_autoreap, METH_VARARGS,
+ "Ensure that zombie children are automatically reaped by the OS." },
+ { NULL, NULL, 0, NULL }
+};
+
+PyMODINIT_FUNC initxu(void)
+{
+ PyObject *m, *d;
+
+ m = Py_InitModule(XENPKG, xu_methods);
+
+ d = PyModule_GetDict(m);
+ port_error = PyErr_NewException(XENPKG ".PortError", NULL, NULL);
+ PyDict_SetItemString(d, "PortError", port_error);
+}
--- /dev/null
+"""Bridge control utilities.
+"""
+import os
+import os.path
+import re
+import sys
+
+os.defpath = os.defpath + ':/sbin:/usr/sbin:/usr/local/sbin'
+CMD_IFCONFIG = 'ifconfig'
+CMD_ROUTE = 'route'
+CMD_BRCTL = 'brctl'
+CMD_IPTABLES = "iptables"
+
+opts = None
+
+class Opts:
+
+ def __init__(self, defaults):
+ for (k, v) in defaults.items():
+ setattr(self, k, v)
+ pass
+
+def cmd(p, s):
+ """Print and execute command 'p' with args 's'.
+ """
+ global opts
+ c = p + ' ' + s
+ if opts.verbose: print c
+ if not opts.dryrun:
+ os.system(c)
+
+def vif_bridge_add(params):
+ """Add the network interface for vif on dom to a bridge.
+ """
+ cmd(CMD_BRCTL, 'addif %(bridge)s %(vif)s' % params)
+
+def vif_bridge_rem(params):
+ """Remove the network interface for vif on dom from a bridge.
+ """
+ cmd(CMD_BRCTL, 'delif %(bridge)s %(vif)s' % params)
+
+def vif_restrict_addr(vif, addr, delete=0):
+ d = { 'vif': vif, 'addr': addr}
+ if delete:
+ d['flag'] = '-D'
+ else:
+ d['flag'] = '-A'
+ cmd(CMD_IPTABLES, '-P FORWARD DROP')
+ cmd(CMD_IPTABLES, '%(flag)s FORWARD -m physdev --physdev-in %(vif)s -s %(addr)s -j ACCEPT' % d)
+ cmd(CMD_IPTABLES, '%(flag)s FORWARD -m physdev --physdev-out %(vif)s -d %(addr)s -j ACCEPT' % d)
+
+def bridge_create(bridge, **kwd):
+ """Create a bridge.
+ Defaults hello time to 0, forward delay to 0 and stp off.
+ """
+ cmd(CMD_BRCTL, 'addbr %s' % bridge)
+ if kwd.get('hello', None) is None:
+ kwd['hello'] = 0
+ if kwd.get('fd', None) is None:
+ kwd['fd'] = 0
+ if kwd.get('stp', None) is None:
+ kwd['stp'] = 'off'
+ bridge_set(bridge, **kwd)
+
+def bridge_set(bridge, hello=None, fd=None, stp=None):
+ """Set bridge parameters.
+ """
+ if hello is not None:
+ cmd(CMD_BRCTL, 'sethello %s %d' % (bridge, hello))
+ if fd is not None:
+ cmd(CMD_BRCTL, 'setfd %s %d' % (bridge, fd))
+ if stp is not None:
+ cmd(CMD_BRCTL, 'stp %s %s' % (bridge, stp))
+
+def bridge_del(bridge):
+ """Delete a bridge.
+ """
+ cmd(CMD_BRCTL, 'delbr %s' % bridge)
+
+def routes():
+ """Return a list of the routes.
+ """
+ fin = os.popen(CMD_ROUTE + ' -n', 'r')
+ routes = []
+ for x in fin:
+ if x.startswith('Kernel'): continue
+ if x.startswith('Destination'): continue
+ x = x.strip()
+ y = x.split()
+ z = { 'destination': y[0],
+ 'gateway' : y[1],
+ 'mask' : y[2],
+ 'flags' : y[3],
+ 'metric' : y[4],
+ 'ref' : y[5],
+ 'use' : y[6],
+ 'interface' : y[7] }
+ routes.append(z)
+ return routes
+
+def ifconfig(interface):
+ """Return the ip config for an interface,
+ """
+ fin = os.popen(CMD_IFCONFIG + ' %s' % interface, 'r')
+ inetre = re.compile('\s*inet\s*addr:(?P<address>\S*)\s*Bcast:(?P<broadcast>\S*)\s*Mask:(?P<mask>\S*)')
+ info = None
+ for x in fin:
+ m = inetre.match(x)
+ if not m: continue
+ info = m.groupdict()
+ info['interface'] = interface
+ break
+ return info
+
+def reconfigure(interface, bridge):
+ """Reconfigure an interface to be attached to a bridge, and give the bridge
+ the IP address etc. from interface. Move the default route to the interface
+ to the bridge.
+
+ """
+ global opts
+ intf_info = ifconfig(interface)
+ if not intf_info:
+ print >>sys.stderr, 'Interface not found:', interface
+ return
+ #bridge_info = ifconfig(bridge)
+ #if not bridge_info:
+ # print >>sys.stderr, 'Bridge not found:', bridge
+ # return
+ route_info = routes()
+ intf_info['bridge'] = bridge
+ intf_info['gateway'] = None
+ for r in route_info:
+ if (r['destination'] == '0.0.0.0' and
+ 'G' in r['flags'] and
+ r['interface'] == interface):
+ intf_info['gateway'] = r['gateway']
+ if not intf_info['gateway']:
+ print >>sys.stderr, 'Gateway not found: ', interface
+ return
+ cmd(CMD_IFCONFIG,
+ '%(bridge)s %(address)s netmask %(mask)s broadcast %(broadcast)s up'
+ % intf_info)
+ cmd(CMD_ROUTE,
+ 'add default gateway %(gateway)s dev %(bridge)s'
+ % intf_info)
+ cmd(CMD_BRCTL, 'addif %(bridge)s %(interface)s' % intf_info)
+ cmd(CMD_IFCONFIG, '%(interface)s 0.0.0.0' % intf_info)
+
+defaults = {
+ 'verbose' : 1,
+ 'dryrun' : 0,
+ }
+
+opts = Opts(defaults)
+
+def set_opts(val):
+ global opts
+ opts = val
+ return opts
--- /dev/null
+#!/usr/bin/env python
+
+##############################################
+# Console client for Xen guest OSes
+# Copyright (c) 2004, K A Fraser
+##############################################
+
+import errno, os, signal, socket, struct, sys
+
+from termios import *
+# Indexes into termios.tcgetattr() list.
+IFLAG = 0
+OFLAG = 1
+CFLAG = 2
+LFLAG = 3
+ISPEED = 4
+OSPEED = 5
+CC = 6
+
+def __child_death(signum, frame):
+ global stop
+ stop = True
+
+def __recv_from_sock(sock):
+ global stop
+ stop = False
+ while not stop:
+ try:
+ data = sock.recv(1024)
+ os.write(1, data)
+ except socket.error, error:
+ if error[0] != errno.EINTR:
+ raise
+ os.wait()
+
+def __send_to_sock(sock):
+ while 1:
+ data = os.read(0,1024)
+ if ord(data[0]) == ord(']')-64:
+ break
+ try:
+ sock.send(data)
+ except socket.error, error:
+ if error[0] == errno.EPIPE:
+ sys.exit(0)
+ if error[0] != errno.EINTR:
+ raise
+ sys.exit(0)
+
+def connect(host,port):
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
+ sock.connect((host,port))
+
+ oattrs = tcgetattr(0)
+ nattrs = tcgetattr(0)
+ nattrs[IFLAG] = nattrs[IFLAG] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON)
+ nattrs[OFLAG] = nattrs[OFLAG] & ~(OPOST)
+ nattrs[CFLAG] = nattrs[CFLAG] & ~(CSIZE | PARENB)
+ nattrs[CFLAG] = nattrs[CFLAG] | CS8
+ nattrs[LFLAG] = nattrs[LFLAG] & ~(ECHO | ICANON | IEXTEN | ISIG)
+ nattrs[CC][VMIN] = 1
+ nattrs[CC][VTIME] = 0
+
+ if os.fork():
+ signal.signal(signal.SIGCHLD, __child_death)
+ print "************ REMOTE CONSOLE: CTRL-] TO QUIT ********"
+ tcsetattr(0, TCSAFLUSH, nattrs)
+ try:
+ __recv_from_sock(sock)
+ finally:
+ tcsetattr(0, TCSAFLUSH, oattrs)
+ print
+ print "************ REMOTE CONSOLE EXITED *****************"
+ else:
+ signal.signal(signal.SIGPIPE, signal.SIG_IGN)
+ __send_to_sock(sock)
+
+if __name__ == '__main__':
+ if len(sys.argv) != 3:
+ print sys.argv[0] + " <host> <port>"
+ sys.exit(1)
+ connect(str(sys.argv[1]),int(sys.argv[2]))
--- /dev/null
+import os
+import re
+import socket
+import struct
+
+def readlines(fd):
+ """Version of readlines safe against EINTR.
+ """
+ import errno
+
+ lines = []
+ while 1:
+ try:
+ line = fd.readline()
+ except IOError, ex:
+ if ex.errno == errno.EINTR:
+ continue
+ else:
+ raise
+ if line == '': break
+ lines.append(line)
+ return lines
+
+def readline(fd):
+ """Version of readline safe against EINTR.
+ """
+ while 1:
+ try:
+ return fd.readline()
+ except IOError, ex:
+ if ex.errno == errno.EINTR:
+ continue
+ else:
+ raise
+
+##### Networking-related functions
+
+"""Bridge for network backend.
+When bridging is used, eth0 may not have an IP address,
+as it may have been moved onto the bridge.
+"""
+NBE_BRIDGE = 'nbe-br'
+
+def get_current_ipaddr(dev='eth0'):
+ """Return a string containing the primary IP address for the given
+ network interface (default 'eth0').
+ """
+ fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
+ lines = readlines(fd)
+ for line in lines:
+ m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
+ line )
+ if m:
+ return m.group(1)
+ if dev == 'eth0':
+ return get_current_ipaddr(NBE_BRIDGE)
+ return None
+
+def get_current_ipmask(dev='eth0'):
+ """Return a string containing the primary IP netmask for the given
+ network interface (default 'eth0').
+ """
+ fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
+ lines = readlines(fd)
+ for line in lines:
+ m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
+ line )
+ if m:
+ return m.group(1)
+ if dev == 'eth0':
+ return get_current_ipmask(NBE_BRIDGE)
+ return None
+
+def get_current_ipgw(dev='eth0'):
+ """Return a string containing the IP gateway for the given
+ network interface (default 'eth0').
+ """
+ fd = os.popen( '/sbin/route -n' )
+ lines = readlines(fd)
+ for line in lines:
+ m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' +
+ '\s+\S+\s+\S*G.*' + dev + '.*', line )
+ if m:
+ return m.group(1)
+ if dev == 'eth0':
+ return get_current_ipgw(NBE_BRIDGE)
+ return None
+
+def inet_aton(addr):
+ """Convert an IP addr in IPv4 dot notation into an int.
+ """
+ b = socket.inet_aton(addr)
+ return struct.unpack('!I', b)[0]
+
+def inet_ntoa(n):
+ """Convert an int into an IP addr in IPv4 dot notation.
+ """
+ b = struct.pack('!I', n)
+ return socket.inet_ntoa(b)
+
+def add_offset_to_ip(addr, offset):
+ """Add a numerical offset to an IP addr in IPv4 dot notation.
+ """
+ n = inet_aton(addr)
+ n += offset
+ return inet_ntoa(n)
+
+def check_subnet( ip, network, netmask ):
+ n_ip = inet_aton(ip)
+ n_net = inet_aton(network)
+ n_mask = inet_aton(netmask)
+ return (n_ip & n_mask) == (n_net & n_mask)
+
--- /dev/null
+"""Temporary files.
+
+This module provides generic, low- and high-level interfaces for
+creating temporary files and directories. The interfaces listed
+as "safe" just below can be used without fear of race conditions.
+Those listed as "unsafe" cannot, and are provided for backward
+compatibility only.
+
+This module also provides some data items to the user:
+
+ TMP_MAX - maximum number of names that will be tried before
+ giving up.
+ template - the default prefix for all temporary names.
+ You may change this to control the default prefix.
+ tempdir - If this is set to a string before the first use of
+ any routine from this module, it will be considered as
+ another candidate location to store temporary files.
+"""
+
+__all__ = [
+ "NamedTemporaryFile", "TemporaryFile", # high level safe interfaces
+ "mkstemp", "mkdtemp", # low level safe interfaces
+ "mktemp", # deprecated unsafe interface
+ "TMP_MAX", "gettempprefix", # constants
+ "tempdir", "gettempdir"
+ ]
+
+
+# Imports.
+
+import os as _os
+import errno as _errno
+from random import Random as _Random
+
+if _os.name == 'mac':
+ import Carbon.Folder as _Folder
+ import Carbon.Folders as _Folders
+
+try:
+ import fcntl as _fcntl
+ # If PYTHONCASEOK is set on Windows, stinking FCNTL.py gets
+ # imported, and we don't get an ImportError then. Provoke
+ # an AttributeError instead in that case.
+ _fcntl.fcntl
+except (ImportError, AttributeError):
+ def _set_cloexec(fd):
+ pass
+else:
+ def _set_cloexec(fd):
+ flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0)
+ if flags >= 0:
+ # flags read successfully, modify
+ flags |= _fcntl.FD_CLOEXEC
+ _fcntl.fcntl(fd, _fcntl.F_SETFD, flags)
+
+
+try:
+ import thread as _thread
+except ImportError:
+ import dummy_thread as _thread
+_allocate_lock = _thread.allocate_lock
+
+_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL
+if hasattr(_os, 'O_NOINHERIT'):
+ _text_openflags |= _os.O_NOINHERIT
+if hasattr(_os, 'O_NOFOLLOW'):
+ _text_openflags |= _os.O_NOFOLLOW
+
+_bin_openflags = _text_openflags
+if hasattr(_os, 'O_BINARY'):
+ _bin_openflags |= _os.O_BINARY
+
+if hasattr(_os, 'TMP_MAX'):
+ TMP_MAX = _os.TMP_MAX
+else:
+ TMP_MAX = 10000
+
+template = "tmp"
+
+tempdir = None
+
+# Internal routines.
+
+_once_lock = _allocate_lock()
+
+class _RandomNameSequence:
+ """An instance of _RandomNameSequence generates an endless
+ sequence of unpredictable strings which can safely be incorporated
+ into file names. Each string is six characters long. Multiple
+ threads can safely use the same instance at the same time.
+
+ _RandomNameSequence is an iterator."""
+
+ characters = ("abcdefghijklmnopqrstuvwxyz" +
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
+ "0123456789-_")
+
+ def __init__(self):
+ self.mutex = _allocate_lock()
+ self.rng = _Random()
+ self.normcase = _os.path.normcase
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ m = self.mutex
+ c = self.characters
+ choose = self.rng.choice
+
+ m.acquire()
+ try:
+ letters = [choose(c) for dummy in "123456"]
+ finally:
+ m.release()
+
+ return self.normcase(''.join(letters))
+
+def _candidate_tempdir_list():
+ """Generate a list of candidate temporary directories which
+ _get_default_tempdir will try."""
+
+ dirlist = []
+
+ # First, try the environment.
+ for envname in 'TMPDIR', 'TEMP', 'TMP':
+ dirname = _os.getenv(envname)
+ if dirname: dirlist.append(dirname)
+
+ # Failing that, try OS-specific locations.
+ if _os.name == 'mac':
+ try:
+ fsr = _Folder.FSFindFolder(_Folders.kOnSystemDisk,
+ _Folders.kTemporaryFolderType, 1)
+ dirname = fsr.as_pathname()
+ dirlist.append(dirname)
+ except _Folder.error:
+ pass
+ elif _os.name == 'riscos':
+ dirname = _os.getenv('Wimp$ScrapDir')
+ if dirname: dirlist.append(dirname)
+ elif _os.name == 'nt':
+ dirlist.extend([ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ])
+ else:
+ dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ])
+
+ # As a last resort, the current directory.
+ try:
+ dirlist.append(_os.getcwd())
+ except (AttributeError, _os.error):
+ dirlist.append(_os.curdir)
+
+ return dirlist
+
+def _get_default_tempdir():
+ """Calculate the default directory to use for temporary files.
+ This routine should be called exactly once.
+
+ We determine whether or not a candidate temp dir is usable by
+ trying to create and write to a file in that directory. If this
+ is successful, the test file is deleted. To prevent denial of
+ service, the name of the test file must be randomized."""
+
+ namer = _RandomNameSequence()
+ dirlist = _candidate_tempdir_list()
+ flags = _text_openflags
+
+ for dir in dirlist:
+ if dir != _os.curdir:
+ dir = _os.path.normcase(_os.path.abspath(dir))
+ # Try only a few names per directory.
+ for seq in xrange(100):
+ name = namer.next()
+ filename = _os.path.join(dir, name)
+ try:
+ fd = _os.open(filename, flags, 0600)
+ fp = _os.fdopen(fd, 'w')
+ fp.write('blat')
+ fp.close()
+ _os.unlink(filename)
+ del fp, fd
+ return dir
+ except (OSError, IOError), e:
+ if e[0] != _errno.EEXIST:
+ break # no point trying more names in this directory
+ pass
+ raise IOError, (_errno.ENOENT,
+ ("No usable temporary directory found in %s" % dirlist))
+
+_name_sequence = None
+
+def _get_candidate_names():
+ """Common setup sequence for all user-callable interfaces."""
+
+ global _name_sequence
+ if _name_sequence is None:
+ _once_lock.acquire()
+ try:
+ if _name_sequence is None:
+ _name_sequence = _RandomNameSequence()
+ finally:
+ _once_lock.release()
+ return _name_sequence
+
+
+def _mkstemp_inner(dir, pre, suf, flags):
+ """Code common to mkstemp, TemporaryFile, and NamedTemporaryFile."""
+
+ names = _get_candidate_names()
+
+ for seq in xrange(TMP_MAX):
+ name = names.next()
+ file = _os.path.join(dir, pre + name + suf)
+ try:
+ fd = _os.open(file, flags, 0600)
+ _set_cloexec(fd)
+ return (fd, file)
+ except OSError, e:
+ if e.errno == _errno.EEXIST:
+ continue # try again
+ raise
+
+ raise IOError, (_errno.EEXIST, "No usable temporary file name found")
+
+
+# User visible interfaces.
+
+def gettempprefix():
+ """Accessor for tempdir.template."""
+ return template
+
+tempdir = None
+
+def gettempdir():
+ """Accessor for tempdir.tempdir."""
+ global tempdir
+ if tempdir is None:
+ _once_lock.acquire()
+ try:
+ if tempdir is None:
+ tempdir = _get_default_tempdir()
+ finally:
+ _once_lock.release()
+ return tempdir
+
+def mkstemp(suffix="", prefix=template, dir=None, text=False):
+ """mkstemp([suffix, [prefix, [dir, [text]]]])
+ User-callable function to create and return a unique temporary
+ file. The return value is a pair (fd, name) where fd is the
+ file descriptor returned by os.open, and name is the filename.
+
+ If 'suffix' is specified, the file name will end with that suffix,
+ otherwise there will be no suffix.
+
+ If 'prefix' is specified, the file name will begin with that prefix,
+ otherwise a default prefix is used.
+
+ If 'dir' is specified, the file will be created in that directory,
+ otherwise a default directory is used.
+
+ If 'text' is specified and true, the file is opened in text
+ mode. Else (the default) the file is opened in binary mode. On
+ some operating systems, this makes no difference.
+
+ The file is readable and writable only by the creating user ID.
+ If the operating system uses permission bits to indicate whether a
+ file is executable, the file is executable by no one. The file
+ descriptor is not inherited by children of this process.
+
+ Caller is responsible for deleting the file when done with it.
+ """
+
+ if dir is None:
+ dir = gettempdir()
+
+ if text:
+ flags = _text_openflags
+ else:
+ flags = _bin_openflags
+
+ return _mkstemp_inner(dir, prefix, suffix, flags)
+
+
+def mkdtemp(suffix="", prefix=template, dir=None):
+ """mkdtemp([suffix, [prefix, [dir]]])
+ User-callable function to create and return a unique temporary
+ directory. The return value is the pathname of the directory.
+
+ Arguments are as for mkstemp, except that the 'text' argument is
+ not accepted.
+
+ The directory is readable, writable, and searchable only by the
+ creating user.
+
+ Caller is responsible for deleting the directory when done with it.
+ """
+
+ if dir is None:
+ dir = gettempdir()
+
+ names = _get_candidate_names()
+
+ for seq in xrange(TMP_MAX):
+ name = names.next()
+ file = _os.path.join(dir, prefix + name + suffix)
+ try:
+ _os.mkdir(file, 0700)
+ return file
+ except OSError, e:
+ if e.errno == _errno.EEXIST:
+ continue # try again
+ raise
+
+ raise IOError, (_errno.EEXIST, "No usable temporary directory name found")
+
+def mktemp(suffix="", prefix=template, dir=None):
+ """mktemp([suffix, [prefix, [dir]]])
+ User-callable function to return a unique temporary file name. The
+ file is not created.
+
+ Arguments are as for mkstemp, except that the 'text' argument is
+ not accepted.
+
+ This function is unsafe and should not be used. The file name
+ refers to a file that did not exist at some point, but by the time
+ you get around to creating it, someone else may have beaten you to
+ the punch.
+ """
+
+## from warnings import warn as _warn
+## _warn("mktemp is a potential security risk to your program",
+## RuntimeWarning, stacklevel=2)
+
+ if dir is None:
+ dir = gettempdir()
+
+ names = _get_candidate_names()
+ for seq in xrange(TMP_MAX):
+ name = names.next()
+ file = _os.path.join(dir, prefix + name + suffix)
+ if not _os.path.exists(file):
+ return file
+
+ raise IOError, (_errno.EEXIST, "No usable temporary filename found")
+
+class _TemporaryFileWrapper:
+ """Temporary file wrapper
+
+ This class provides a wrapper around files opened for
+ temporary use. In particular, it seeks to automatically
+ remove the file when it is no longer needed.
+ """
+
+ def __init__(self, file, name):
+ self.file = file
+ self.name = name
+ self.close_called = False
+
+ def __getattr__(self, name):
+ file = self.__dict__['file']
+ a = getattr(file, name)
+ if type(a) != type(0):
+ setattr(self, name, a)
+ return a
+
+ # NT provides delete-on-close as a primitive, so we don't need
+ # the wrapper to do anything special. We still use it so that
+ # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile.
+ if _os.name != 'nt':
+
+ # Cache the unlinker so we don't get spurious errors at
+ # shutdown when the module-level "os" is None'd out. Note
+ # that this must be referenced as self.unlink, because the
+ # name TemporaryFileWrapper may also get None'd out before
+ # __del__ is called.
+ unlink = _os.unlink
+
+ def close(self):
+ if not self.close_called:
+ self.close_called = True
+ self.file.close()
+ self.unlink(self.name)
+
+ def __del__(self):
+ self.close()
+
+def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="",
+ prefix=template, dir=None):
+ """Create and return a temporary file.
+ Arguments:
+ 'prefix', 'suffix', 'dir' -- as for mkstemp.
+ 'mode' -- the mode argument to os.fdopen (default "w+b").
+ 'bufsize' -- the buffer size argument to os.fdopen (default -1).
+ The file is created as mkstemp() would do it.
+
+ Returns a file object; the name of the file is accessible as
+ file.name. The file will be automatically deleted when it is
+ closed.
+ """
+
+ if dir is None:
+ dir = gettempdir()
+
+ if 'b' in mode:
+ flags = _bin_openflags
+ else:
+ flags = _text_openflags
+
+ # Setting O_TEMPORARY in the flags causes the OS to delete
+ # the file when it is closed. This is only supported by Windows.
+ if _os.name == 'nt':
+ flags |= _os.O_TEMPORARY
+
+ (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)
+ file = _os.fdopen(fd, mode, bufsize)
+ return _TemporaryFileWrapper(file, name)
+
+if _os.name != 'posix' or _os.sys.platform == 'cygwin':
+ # On non-POSIX and Cygwin systems, assume that we cannot unlink a file
+ # while it is open.
+ TemporaryFile = NamedTemporaryFile
+
+else:
+ def TemporaryFile(mode='w+b', bufsize=-1, suffix="",
+ prefix=template, dir=None):
+ """Create and return a temporary file.
+ Arguments:
+ 'prefix', 'suffix', 'directory' -- as for mkstemp.
+ 'mode' -- the mode argument to os.fdopen (default "w+b").
+ 'bufsize' -- the buffer size argument to os.fdopen (default -1).
+ The file is created as mkstemp() would do it.
+
+ Returns a file object. The file has no name, and will cease to
+ exist when it is closed.
+ """
+
+ if dir is None:
+ dir = gettempdir()
+
+ if 'b' in mode:
+ flags = _bin_openflags
+ else:
+ flags = _text_openflags
+
+ (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)
+ try:
+ _os.unlink(name)
+ return _os.fdopen(fd, mode, bufsize)
+ except:
+ _os.close(fd)
+ raise
--- /dev/null
+import sxp
+
+class ArgError(StandardError):
+ pass
+
+class Args:
+ """Argument encoding support for HTTP.
+ """
+
+ def __init__(self, paramspec, keyspec):
+ self.arg_ord = []
+ self.arg_dict = {}
+ self.key_ord = []
+ self.key_dict = {}
+ for (name, type) in paramspec:
+ self.arg_ord.append(name)
+ self.arg_dict[name] = type
+ for (name, type) in keyspec:
+ self.key_ord.append(name)
+ self.key_dict[name] = type
+
+ def get_args(self, d, xargs=None):
+ args = {}
+ keys = {}
+ params = []
+ if xargs:
+ self.split_args(xargs, args, keys)
+ self.split_args(d, args, keys)
+ for a in self.arg_ord:
+ if a in args:
+ params.append(args[a])
+ else:
+ raise ArgError('Missing parameter: %s' % a)
+ return (params, keys)
+
+ def split_args(self, d, args, keys):
+ for (k, v) in d.items():
+ if k in self.arg_dict:
+ type = self.arg_dict[k]
+ val = self.coerce(type, v)
+ args[k] = val
+ elif k in self.key_dict:
+ type = self.key_dict[k]
+ val = self.coerce(type, v)
+ keys[k] = val
+ else:
+ raise ArgError('Invalid parameter: %s' % k)
+
+ def get_form_args(self, f, xargs=None):
+ d = {}
+ for (k, v) in f.items():
+ n = len(v)
+ if ((k not in self.arg_dict) and
+ (k not in self.key_dict)):
+ continue
+ if n == 0:
+ continue
+ elif n == 1:
+ d[k] = v[0]
+ else:
+ raise ArgError('Too many values for %s' % k)
+ return self.get_args(d, xargs=xargs)
+
+ def coerce(self, type, v):
+ try:
+ if type == 'int':
+ return int(v)
+ if type == 'str':
+ return str(v)
+ if type == 'sxpr':
+ return self.sxpr(v)
+ except ArgError:
+ raise
+ except StandardError, ex:
+ raise ArgError(str(ex))
+
+ def sxpr(self, v):
+ if instanceof(v, types.ListType):
+ return v
+ if instanceof(v, types.File) or hasattr(v, 'readline'):
+ return sxpr_file(v)
+ if instanceof(v, types.StringType):
+ return sxpr_file(StringIO(v))
+ return str(v)
+
+ def sxpr_file(self, fin):
+ try:
+ vals = sxp.parse(fin)
+ except:
+ raise ArgError('Coercion to sxpr failed')
+ if len(vals) == 1:
+ return vals[0]
+ else:
+ raise ArgError('Too many sxprs')
+
+ def call_with_args(self, fn, args, xargs=None):
+ (params, keys) = self.get_args(args, xargs=xargs)
+ fn(*params, **keys)
+
+ def call_with_form_args(self, fn, fargs, xargs=None):
+ (params, keys) = self.get_form_args(fargs, xargs=xargs)
+ fn(*params, **keys)
+
+class ArgFn(Args):
+ """Represent a remote HTTP operation as a function.
+ Used on the client.
+ """
+
+ def __init__(self, fn, paramspec, keyspec={}):
+ Args.__init__(self, paramspec, keyspec)
+ self.fn = fn
+
+ def __call__(self, fargs, xargs=None):
+ return self.call_with_args(self.fn, fargs, xargs=xargs)
+
+class FormFn(Args):
+ """Represent an operation as a function over a form.
+ Used in the HTTP server.
+ """
+
+ def __init__(self, fn, paramspec, keyspec={}):
+ Args.__init__(self, paramspec, keyspec)
+ self.fn = fn
+
+ def __call__(self, fargs, xargs=None):
+ return self.call_with_form_args(self.fn, fargs, xargs=xargs)
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+"""Simple publish/subscribe event server.
+
+"""
+import string
+
+from twisted.internet import reactor
+
+# subscribe a.b.c h: map a.b.c -> h
+# subscribe a.b.* h: map a.b.* -> h
+# subscribe a.b.? h: map a.b.? -> h
+#
+# for event a.b.c.d:
+#
+# lookup a.b.c.d, call handlers
+#
+# lookup a.b.c.?, call handlers
+#
+# lookup a.b.c.d.*, call handlers
+# lookup a.b.c.*, call handlers
+# lookup a.b.*, call handlers
+# lookup a.*, call handlers
+# lookup *, call handlers
+
+# a.b.c.d = (a b c d)
+# a.b.c.? = (a b c _)
+# a.b.c.* = (a b c . _)
+
+class EventServer:
+
+ DOT = '.'
+ QUERY = '?'
+ DOT_QUERY = DOT + QUERY
+ STAR = '*'
+ DOT_STAR = DOT + STAR
+
+ def __init__(self, run=0):
+ self.handlers = {}
+ self.run = run
+ self.queue = []
+
+ def start(self):
+ """Enable event handling. Sends any queued events.
+ """
+ self.run = 1
+ for (e,v) in self.queue:
+ self.inject(e, v)
+ self.queue = []
+
+ def stop(self):
+ """Suspend event handling. Events injected while suspended
+ are queued until we are started again.
+ """
+ self.run = 0
+
+ def subscribe(self, event, handler):
+ """Subscribe to an event. For example 'a.b.c.d'.
+ A subcription like 'a.b.c.?' ending in '?' matches any value
+ for the '?'. A subscription like 'a.b.c.*' ending in '*' matches
+ any event type with the same prefix, 'a.b.c' in this case.
+
+ event event name
+ handler event handler fn(event, val)
+ """
+ hl = self.handlers.get(event)
+ if hl is None:
+ self.handlers[event] = [handler]
+ else:
+ hl.append(handler)
+
+ def unsubscribe_all(self, event=None):
+ """Unsubscribe all handlers for a given event, or all handlers.
+
+ event event (optional)
+ """
+ if event == None:
+ self.handlers.clear()
+ elif event in self.handlers:
+ del self.handlers[event]
+
+ def unsubscribe(self, event, handler):
+ """Unsubscribe a given event and handler.
+
+ event event
+ handler handler
+ """
+ hl = self.handlers.get(event)
+ if hl is None:
+ return
+ if handler in hl:
+ hl.remove(handler)
+
+ def inject(self, event, val, async=1):
+ """Inject an event. Handlers for it are called if running, otherwise
+ it is queued.
+
+ event event type
+ val event value
+ """
+ if self.run:
+ if async:
+ reactor.callLater(0, self.call_handlers, event, val)
+ else:
+ self.notify_handlers(event, val)
+ else:
+ self.queue.append( (event, val) )
+
+ def call_handlers(self, event, val):
+ """Internal method to call event handlers.
+ """
+ #print ">event", event, val
+ self.call_event_handlers(event, event, val)
+ self.call_query_handlers(event, val)
+ self.call_star_handlers(event, val)
+
+ def call_event_handlers(self, key, event, val):
+ """Call the handlers for an event.
+ It is safe for handlers to subscribe or unsubscribe.
+
+ key key for handler list
+ event event type
+ val event value
+ """
+ hl = self.handlers.get(key)
+ if hl is None:
+ return
+ # Copy the handler list so that handlers can call
+ # subscribe/unsubscribe safely - python list iteration
+ # is not safe against list modification.
+ for h in hl[:]:
+ try:
+ h(event, val)
+ except:
+ pass
+
+ def call_query_handlers(self, event, val):
+ """Call regex handlers for events matching 'event' that end in '?'.
+
+ event event type
+ val event value
+ """
+ dot_idx = event.rfind(self.DOT)
+ if dot_idx == -1:
+ self.call_event_handlers(self.QUERY, event, val)
+ else:
+ event_query = event[0:dot_idx] + self.DOT_QUERY
+ self.call_event_handlers(event_query, event, val)
+
+ def call_star_handlers(self, event, val):
+ """Call regex handlers for events matching 'event' that end in '*'.
+
+ event event type
+ val event value
+ """
+ etype = string.split(event, self.DOT)
+ for i in range(len(etype), 0, -1):
+ event_star = self.DOT.join(etype[0:i]) + self.DOT_STAR
+ self.call_event_handlers(event_star, event, val)
+ self.call_event_handlers(self.STAR, event, val)
+
+def instance():
+ global inst
+ try:
+ inst
+ except:
+ inst = EventServer()
+ inst.start()
+ return inst
+
+def main():
+ def sys_star(event, val):
+ print 'sys_star', event, val
+
+ def sys_foo(event, val):
+ print 'sys_foo', event, val
+ s.unsubscribe('sys.foo', sys_foo)
+
+ def sys_foo2(event, val):
+ print 'sys_foo2', event, val
+
+ def sys_bar(event, val):
+ print 'sys_bar', event, val
+
+ def sys_foo_bar(event, val):
+ print 'sys_foo_bar', event, val
+
+ def foo_bar(event, val):
+ print 'foo_bar', event, val
+
+ s = EventServer()
+ s.start()
+ s.subscribe('sys.*', sys_star)
+ s.subscribe('sys.foo', sys_foo)
+ s.subscribe('sys.foo', sys_foo2)
+ s.subscribe('sys.bar', sys_bar)
+ s.subscribe('sys.foo.bar', sys_foo_bar)
+ s.subscribe('foo.bar', foo_bar)
+ s.inject('sys.foo', 'hello')
+ print
+ s.inject('sys.bar', 'hello again')
+ print
+ s.inject('sys.foo.bar', 'hello again')
+ print
+ s.inject('foo.bar', 'hello again')
+ print
+ s.inject('foo', 'hello again')
+ print
+ s.start()
+ s.unsubscribe('sys.*', sys_star)
+ s.unsubscribe_all('sys.*')
+ s.inject('sys.foo', 'hello')
+
+if __name__ == "__main__":
+ main()
+
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+## XEND_DOMAIN_CREATE = "xend.domain.create": dom
+## create:
+## xend.domain.destroy: dom, reason:died/crashed
+## xend.domain.up ?
+
+## xend.domain.unpause: dom
+## xend.domain.pause: dom
+## xend.domain.shutdown: dom
+## xend.domain.destroy: dom
+
+## xend.domain.migrate.begin: dom, to
+## Begin tells: src host, src domain uri, dst host. Dst id known?
+## err: src host, src domain uri, dst host, dst id if known, status (of domain: ok, dead,...), reason
+## end: src host, src domain uri, dst host, dst uri
+
+## Events for both ends of migrate: for exporter and importer?
+## Include migrate id so can tie together.
+## Have uri /xend/migrate/<id> for migrate info (migrations in progress).
+
+## (xend.domain.migrate.begin (src <host>) (src.domain <id>)
+## (dst <host>) (id <migrate id>))
+
+## xend.domain.migrate.end:
+## (xend.domain.migrate.end (domain <id>) (to <host>)
+
+## xend.node.up: xend uri
+## xend.node.down: xend uri
+
+## xend.error ?
+
+## format:
+
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+"""General pretty-printer, including support for SXP.
+
+"""
+import sys
+import types
+import StringIO
+import sxp
+
+class PrettyItem:
+
+ def __init__(self, width):
+ self.width = width
+
+ def insert(self, block):
+ block.addtoline(self)
+
+ def get_width(self):
+ return self.width
+
+ def output(self, out):
+ print '***PrettyItem>output>', self
+ pass
+
+ def prettyprint(self, out, width):
+ print '***PrettyItem>prettyprint>', self
+ return width
+
+class PrettyString(PrettyItem):
+
+ def __init__(self, x):
+ PrettyItem.__init__(self, len(x))
+ self.value = x
+
+ def output(self, out):
+ out.write(self.value)
+
+ def prettyprint(self, line):
+ line.output(self)
+
+ def show(self, out):
+ print >> out, ("(string (width %d) '%s')" % (self.width, self.value))
+
+class PrettySpace(PrettyItem):
+
+ def output(self, out):
+ out.write(' ' * self.width)
+
+ def prettyprint(self, line):
+ line.output(self)
+
+ def show(self, out):
+ print >> out, ("(space (width %d))" % self.width)
+
+class PrettyBreak(PrettyItem):
+
+ def __init__(self, width, indent):
+ PrettyItem.__init__(self, width)
+ self.indent = indent
+ self.space = 0
+ self.active = 0
+
+ def output(self, out):
+ out.write(' ' * self.width)
+
+ def prettyprint(self, line):
+ if line.breaks(self.space):
+ self.active = 1
+ line.newline(self.indent)
+ else:
+ line.output(self)
+
+ def show(self, out):
+ print >> out, ("(break (width %d) (indent %d) (space %d) (active %d))"
+ % (self.width, self.indent, self.space, self.lspace, self.active))
+
+class PrettyNewline(PrettySpace):
+
+ def __init__(self, indent):
+ PrettySpace.__init__(self, indent)
+
+ def insert(self, block):
+ block.newline()
+ block.addtoline(self)
+
+ def output(self, out):
+ out.write(' ' * self.width)
+
+ def prettyprint(self, line):
+ line.newline(0)
+ line.output(self)
+
+ def show(self, out):
+ print >> out, ("(nl (indent %d))" % self.indent)
+
+class PrettyLine(PrettyItem):
+ def __init__(self):
+ PrettyItem.__init__(self, 0)
+ self.content = []
+
+ def write(self, x):
+ self.content.append(x)
+
+ def end(self):
+ width = 0
+ lastwidth = 0
+ lastbreak = None
+ for x in self.content:
+ if isinstance(x, PrettyBreak):
+ if lastbreak:
+ lastbreak.space = (width - lastwidth)
+ lastbreak = x
+ lastwidth = width
+ width += x.get_width()
+ if lastbreak:
+ lastbreak.space = (width - lastwidth)
+ self.width = width
+
+ def prettyprint(self, line):
+ for x in self.content:
+ x.prettyprint(line)
+
+ def show(self, out):
+ print >> out, '(LINE (width %d)' % self.width
+ for x in self.content:
+ x.show(out)
+ print >> out, ')'
+
+class PrettyBlock(PrettyItem):
+
+ def __init__(self, all=0, parent=None):
+ self.width = 0
+ self.lines = []
+ self.parent = parent
+ self.indent = 0
+ self.all = all
+ self.broken = 0
+ self.newline()
+
+ def add(self, item):
+ item.insert(self)
+
+ def end(self):
+ self.width = 0
+ for l in self.lines:
+ l.end()
+ if self.width < l.width:
+ self.width = l.width
+
+ def breaks(self, n):
+ return self.all and self.broken
+
+ def newline(self):
+ self.lines.append(PrettyLine())
+
+ def addtoline(self, x):
+ self.lines[-1].write(x)
+
+ def prettyprint(self, line):
+ self.indent = line.used
+ line.block = self
+ if not line.fits(self.width):
+ self.broken = 1
+ for l in self.lines:
+ l.prettyprint(line)
+ line.block = self.parent
+
+ def show(self, out):
+ print >> out, ('(BLOCK (width %d) (indent %d) (all %d) (broken %d)' %
+ (self.width, self.indent, self.all, self.broken))
+ for l in self.lines:
+ l.show(out)
+ print >> out, ')'
+
+class Line:
+
+ def __init__(self, out, width):
+ self.out = out
+ self.width = width
+ self.used = 0
+ self.space = self.width
+
+ def newline(self, indent):
+ indent += self.block.indent
+ self.out.write('\n')
+ self.out.write(' ' * indent)
+ self.used = indent
+ self.space = self.width - self.used
+
+ def fits(self, n):
+ return self.space - n >= 0
+
+ def breaks(self, n):
+ return self.block.breaks(n) or not self.fits(n)
+
+ def output(self, x):
+ n = x.get_width()
+ self.space -= n
+ self.used += n
+ if self.space < 0:
+ self.space = 0
+ x.output(self.out)
+
+class PrettyPrinter:
+ """A prettyprinter based on what I remember of Derek Oppen's
+ prettyprint algorithm from TOPLAS way back.
+ """
+
+ def __init__(self, width=40):
+ self.width = width
+ self.block = None
+ self.top = None
+
+ def write(self, x):
+ self.block.add(PrettyString(x))
+
+ def add(self, item):
+ self.block.add(item)
+
+ def addbreak(self, width=1, indent=4):
+ self.add(PrettyBreak(width, indent))
+
+ def addspace(self, width=1):
+ self.add(PrettySpace(width))
+
+ def addnl(self, indent=0):
+ self.add(PrettyNewline(indent))
+
+ def begin(self, all=0):
+ block = PrettyBlock(all=all, parent=self.block)
+ self.block = block
+
+ def end(self):
+ self.block.end()
+ if self.block.parent:
+ self.block.parent.add(self.block)
+ else:
+ self.top = self.block
+ self.block = self.block.parent
+
+ def prettyprint(self, out=sys.stdout):
+ line = Line(out, self.width)
+ self.top.prettyprint(line)
+
+class SXPPrettyPrinter(PrettyPrinter):
+ """An SXP prettyprinter.
+ """
+
+ def pstring(self, x):
+ io = StringIO.StringIO()
+ sxp.show(x, out=io)
+ io.seek(0)
+ val = io.getvalue()
+ io.close()
+ return val
+
+ def pprint(self, l):
+ if isinstance(l, types.ListType):
+ self.begin(all=1)
+ self.write('(')
+ i = 0
+ for x in l:
+ if(i): self.addbreak()
+ self.pprint(x)
+ i += 1
+ self.addbreak(width=0, indent=0)
+ self.write(')')
+ self.end()
+ else:
+ self.write(self.pstring(l))
+
+def prettyprint(sxpr, out=sys.stdout, width=80):
+ """Prettyprint an SXP form.
+
+ sxpr s-expression
+ out destination
+ width maximum output width
+ """
+ if isinstance(sxpr, types.ListType):
+ pp = SXPPrettyPrinter(width=width)
+ pp.pprint(sxpr)
+ pp.prettyprint(out=out)
+ else:
+ sxp.show(sxpr, out=out)
+ print >> out
+
+def main():
+ pin = sxp.Parser()
+ while 1:
+ buf = sys.stdin.read(100)
+ pin.input(buf)
+ if buf == '': break
+ l = pin.get_val()
+ prettyprint(l, width=80)
+
+if __name__ == "__main__":
+ main()
+
--- /dev/null
+import os
+import os.path
+import sys
+
+VIFCTL = '/etc/xen/xend/vifctl'
+
+def init():
+ os.system(VIFCTL + ' init ')
+
+def up(vif, mac=None, bridge=None, ipaddr=[]):
+ args = ['vif=%s' % vif]
+ if mac:
+ args.append('mac=%s' % mac)
+ if bridge:
+ args.append('bridge=%s' % bridge)
+ if ipaddr:
+ args.append('ipaddr=%s' % ','.join(ipaddr))
+ os.system(VIFCTL + ' up ' + ' '.join(args))
+
+def down(vif, mac=None, bridge=None, ipaddr=[]):
+ args = ['vif=%s' % vif]
+ if mac:
+ args.append('mac=%s' % mac)
+ if bridge:
+ args.append('bridge=%s' % bridge)
+ if ipaddr:
+ args.append('ipaddr=%s' % ','.join(ipaddr))
+ os.system(VIFCTL + ' down ' + ' '.join(args))
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+"""Client API for the HTTP interface on xend.
+Callable as a script - see main().
+"""
+import sys
+import httplib
+import types
+from StringIO import StringIO
+import urlparse
+
+from encode import *
+import sxp
+import PrettyPrint
+
+DEBUG = 0
+
+class Foo(httplib.HTTPResponse):
+
+ def begin(self):
+ fin = self.fp
+ while(1):
+ buf = fin.readline()
+ print "***", buf
+ if buf == '':
+ print
+ sys.exit()
+
+
+def sxprio(sxpr):
+ io = StringIO()
+ sxp.show(sxpr, out=io)
+ print >> io
+ io.seek(0)
+ return io
+
+def fileof(val):
+ """Converter for passing configs.
+ Handles lists, files directly.
+ Assumes a string is a file name and passes its contents.
+ """
+ if isinstance(val, types.ListType):
+ return sxprio(val)
+ if isinstance(val, types.StringType):
+ return file(val)
+ if hasattr(val, 'readlines'):
+ return val
+
+# todo: need to sort of what urls/paths are using for objects.
+# e.g. for domains at the moment return '0'.
+# should probably return abs path w.r.t. server, e.g. /xend/domain/0.
+# As an arg, assume abs path is obj uri, otherwise just id.
+
+# Function to convert to full url: Xend.uri(path), e.g.
+# maps /xend/domain/0 to http://wray-m-3.hpl.hp.com:8000/xend/domain/0
+# And should accept urls for ids?
+
+def urljoin(location, root, prefix='', rest=''):
+ prefix = str(prefix)
+ rest = str(rest)
+ base = 'http://' + location + root + prefix
+ url = urlparse.urljoin(base, rest)
+ return url
+
+def nodeurl(location, root, id=''):
+ return urljoin(location, root, 'node/', id)
+
+def domainurl(location, root, id=''):
+ return urljoin(location, root, 'domain/', id)
+
+def consoleurl(location, root, id=''):
+ return urljoin(location, root, 'console/', id)
+
+def deviceurl(location, root, id=''):
+ return urljoin(location, root, 'device/', id)
+
+def vneturl(location, root, id=''):
+ return urljoin(location, root, 'vnet/', id)
+
+def eventurl(location, root, id=''):
+ return urljoin(location, root, 'event/', id)
+
+def xend_request(url, method, data=None):
+ urlinfo = urlparse.urlparse(url)
+ (uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo
+ if DEBUG: print url, urlinfo
+ if uproto != 'http':
+ raise StandardError('Invalid protocol: ' + uproto)
+ if DEBUG: print '>xend_request', ulocation, upath, method, data
+ (hdr, args) = encode_data(data)
+ if data and method == 'GET':
+ upath += '?' + args
+ args = None
+ if method == "POST" and upath.endswith('/'):
+ upath = upath[:-1]
+ if DEBUG: print "ulocation=", ulocation, "upath=", upath, "args=", args
+ #hdr['User-Agent'] = 'Mozilla'
+ #hdr['Accept'] = 'text/html,text/plain'
+ conn = httplib.HTTPConnection(ulocation)
+ #conn.response_class = Foo
+ if DEBUG: conn.set_debuglevel(1)
+ conn.request(method, upath, args, hdr)
+ resp = conn.getresponse()
+ if DEBUG: print resp.status, resp.reason
+ if DEBUG: print resp.msg.headers
+ if resp.status in [204, 404]:
+ return None
+ if resp.status not in [200, 201, 202, 203]:
+ raise RuntimeError(resp.reason)
+ pin = sxp.Parser()
+ data = resp.read()
+ if DEBUG: print "***data" , data
+ if DEBUG: print "***"
+ pin.input(data);
+ pin.input_eof()
+ conn.close()
+ val = pin.get_val()
+ #if isinstance(val, types.ListType) and sxp.name(val) == 'val':
+ # val = val[1]
+ if isinstance(val, types.ListType) and sxp.name(val) == 'err':
+ raise RuntimeError(val[1])
+ if DEBUG: print '**val='; sxp.show(val); print
+ return val
+
+def xend_get(url, args=None):
+ return xend_request(url, "GET", args)
+
+def xend_call(url, data):
+ return xend_request(url, "POST", data)
+
+class Xend:
+
+ SRV_DEFAULT = "localhost:8000"
+ ROOT_DEFAULT = "/xend/"
+
+ def __init__(self, srv=None, root=None):
+ self.bind(srv, root)
+
+ def bind(self, srv=None, root=None):
+ if srv is None: srv = self.SRV_DEFAULT
+ if root is None: root = self.ROOT_DEFAULT
+ if not root.endswith('/'): root += '/'
+ self.location = srv
+ self.root = root
+
+ def nodeurl(self, id=''):
+ return nodeurl(self.location, self.root, id)
+
+ def domainurl(self, id=''):
+ return domainurl(self.location, self.root, id)
+
+ def consoleurl(self, id=''):
+ return consoleurl(self.location, self.root, id)
+
+ def deviceurl(self, id=''):
+ return deviceurl(self.location, self.root, id)
+
+ def vneturl(self, id=''):
+ return vneturl(self.location, self.root, id)
+
+ def eventurl(self, id=''):
+ return eventurl(self.location, self.root, id)
+
+ def xend(self):
+ return xend_get(urljoin(self.location, self.root))
+
+ def xend_node(self):
+ return xend_get(self.nodeurl())
+
+ def xend_node_cpu_rrobin_slice_set(self, slice):
+ return xend_call(self.nodeurl(),
+ {'op' : 'cpu_rrobin_slice_set',
+ 'slice' : slice })
+
+ def xend_node_cpu_bvt_slice_set(self, slice):
+ return xend_call(self.nodeurl(),
+ {'op' : 'cpu_bvt_slice_set',
+ 'slice' : slice })
+
+ def xend_domains(self):
+ return xend_get(self.domainurl())
+
+ def xend_domain_create(self, conf):
+ return xend_call(self.domainurl(),
+ {'op' : 'create',
+ 'config' : fileof(conf) })
+
+ def xend_domain(self, id):
+ return xend_get(self.domainurl(id))
+
+ def xend_domain_unpause(self, id):
+ return xend_call(self.domainurl(id),
+ {'op' : 'unpause'})
+
+ def xend_domain_pause(self, id):
+ return xend_call(self.domainurl(id),
+ {'op' : 'pause'})
+
+ def xend_domain_shutdown(self, id):
+ return xend_call(self.domainurl(id),
+ {'op' : 'shutdown'})
+
+ def xend_domain_destroy(self, id):
+ return xend_call(self.domainurl(id),
+ {'op' : 'destroy'})
+
+ def xend_domain_save(self, id, filename):
+ return xend_call(self.domainurl(id),
+ {'op' : 'save',
+ 'file' : filename})
+
+ def xend_domain_restore(self, id, filename):
+ return xend_call(self.domainurl(id),
+ {'op' : 'restore',
+ 'file' : filename })
+
+ def xend_domain_migrate(self, id, dst):
+ return xend_call(self.domainurl(id),
+ {'op' : 'migrate',
+ 'destination': dst})
+
+ def xend_domain_pincpu(self, id, cpu):
+ return xend_call(self.domainurl(id),
+ {'op' : 'pincpu',
+ 'cpu' : cpu})
+
+ def xend_domain_cpu_bvt_set(self, id, mcuadv, warp, warpl, warpu):
+ return xend_call(self.domainurl(id),
+ {'op' : 'cpu_bvt_set',
+ 'mcuadv' : mvuadv,
+ 'warp' : warp,
+ 'warpl' : warpl,
+ 'warpu' : warpu })
+
+ def xend_domain_cpu_atropos_set(self, id, period, slice, latency, xtratime):
+ return xend_call(self.domainurl(id),
+ {'op' : 'cpu_atropos_set',
+ 'period' : period,
+ 'slice' : slice,
+ 'latency' : latency,
+ 'xtratime': xtratime })
+
+ def xend_domain_vifs(self, id):
+ return xend_get(self.domainurl(id),
+ { 'op' : 'vifs' })
+
+ def xend_domain_vif_ip_add(self, id, vif, ipaddr):
+ return xend_call(self.domainurl(id),
+ {'op' : 'vif_ip_add',
+ 'vif' : vif,
+ 'ip' : ipaddr })
+
+ def xend_domain_vbds(self, id):
+ return xend_get(self.domainurl(id),
+ {'op' : 'vbds'})
+
+ def xend_domain_vbd(self, id, vbd):
+ return xend_get(self.domainurl(id),
+ {'op' : 'vbd',
+ 'vbd' : vbd})
+
+ def xend_consoles(self):
+ return xend_get(self.consoleurl())
+
+ def xend_console(self, id):
+ return xend_get(self.consoleurl(id))
+
+ def xend_vnets(self):
+ return xend_get(self.vneturl())
+
+ def xend_vnet_create(self, conf):
+ return xend_call(self.vneturl(),
+ {'op': 'create', 'config': fileof(conf) })
+
+ def xend_vnet(self, id):
+ return xend_get(self.vneturl(id))
+
+ def xend_vnet_delete(self, id):
+ return xend_call(self.vneturl(id),
+ {'op': 'delete'})
+
+ def xend_event_inject(self, sxpr):
+ val = xend_call(self.eventurl(),
+ {'op': 'inject', 'event': fileof(sxpr) })
+
+
+def main(argv):
+ """Call an API function:
+
+ python XendClient.py fn args...
+
+ The leading 'xend_' on the function can be omitted.
+ Example:
+
+ > python XendClient.py domains
+ (domain 0 8)
+ > python XendClient.py domain 0
+ (domain (id 0) (name Domain-0) (memory 128))
+ """
+ server = Xend()
+ fn = argv[1]
+ if not fn.startswith('xend'):
+ fn = 'xend_' + fn
+ args = argv[2:]
+ val = getattr(server, fn)(*args)
+ PrettyPrint.prettyprint(val)
+ print
+
+if __name__ == "__main__":
+ main(sys.argv)
+else:
+ server = Xend()
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+import socket
+import xen.ext.xc
+xc = xen.ext.xc.new()
+
+import sxp
+import XendRoot
+xroot = XendRoot.instance()
+import XendDB
+
+import EventServer
+eserver = EventServer.instance()
+
+from xen.xend.server import SrvDaemon
+daemon = SrvDaemon.instance()
+
+class XendConsoleInfo:
+ """Console information record.
+ """
+
+ def __init__(self, console, dom1, port1, dom2, port2, conn=None):
+ self.console = console
+ self.dom1 = int(dom1)
+ self.port1 = int(port1)
+ self.dom2 = int(dom2)
+ self.port2 = int(port2)
+ self.conn = conn
+ #self.id = "%d.%d-%d.%d" % (self.dom1, self.port1, self.dom2, self.port2)
+ self.id = str(port1)
+
+ def __str__(self):
+ s = "console"
+ s += " id=%s" % self.id
+ s += " src=%d.%d" % (self.dom1, self.port1)
+ s += " dst=%d.%d" % (self.dom2, self.port2)
+ s += " port=%s" % self.console
+ if self.conn:
+ s += " conn=%s:%s" % (self.conn[0], self.conn[1])
+ return s
+
+ def sxpr(self):
+ sxpr = ['console',
+ ['id', self.id],
+ ['src', self.dom1, self.port1],
+ ['dst', self.dom2, self.port2],
+ ['port', self.console],
+ ]
+ if self.conn:
+ sxpr.append(['connected', self.conn[0], self.conn[1]])
+ return sxpr
+
+ def connection(self):
+ return self.conn
+
+ def update(self, consinfo):
+ conn = sxp.child(consinfo, 'connected')
+ if conn:
+ self.conn = conn[1:]
+ else:
+ self.conn = None
+
+ def uri(self):
+ """Get the uri to use to connect to the console.
+ This will be a telnet: uri.
+
+ return uri
+ """
+ host = socket.gethostname()
+ return "telnet://%s:%s" % (host, self.console)
+
+class XendConsole:
+
+ dbpath = "console"
+
+ def __init__(self):
+ self.db = XendDB.XendDB(self.dbpath)
+ self.console = {}
+ self.console_db = self.db.fetchall("")
+ if xroot.get_rebooted():
+ print 'XendConsole> rebooted: removing all console info'
+ self.rm_all()
+ eserver.subscribe('xend.domain.died', self.onDomainDied)
+ eserver.subscribe('xend.domain.destroy', self.onDomainDied)
+
+ def rm_all(self):
+ """Remove all console info. Used after reboot.
+ """
+ for (k, v) in self.console_db.items():
+ self._delete_console(k)
+
+ def refresh(self):
+ consoles = daemon.consoles()
+ cons = {}
+ for consinfo in consoles:
+ id = str(sxp.child_value(consinfo, 'id'))
+ cons[id] = consinfo
+ if id not in self.console:
+ self._new_console(consinfo)
+ for c in self.console.values():
+ consinfo = cons.get(c.id)
+ if consinfo:
+ c.update(consinfo)
+ else:
+ self._delete_console(c.id)
+
+ def onDomainDied(self, event, val):
+ dom = int(val)
+ #print 'XendConsole>onDomainDied', 'event', event, "dom=", dom
+ for c in self.consoles():
+ #print 'onDomainDied', "dom=", dom, "dom1=", c.dom1, "dom2=", c.dom2
+ if (c.dom1 == dom) or (c.dom2 == dom):
+ 'XendConsole>onDomainDied', 'delete console dom=', dom
+ ctrl = daemon.get_domain_console(dom)
+ if ctrl:
+ ctrl.close()
+ self._delete_console(c.id)
+
+ def sync(self):
+ self.db.saveall("", self.console_db)
+
+ def sync_console(self, id):
+ self.db.save(id, self.console_db[id])
+
+ def _new_console(self, consinfo):
+ # todo: xen needs a call to get current domain id.
+ dom1 = 0
+ port1 = sxp.child_value(consinfo, 'local_port')
+ dom2 = sxp.child_value(consinfo, 'domain')
+ port2 = sxp.child_value(consinfo, 'remote_port')
+ console = sxp.child_value(consinfo, 'console_port')
+ info = XendConsoleInfo(console, dom1, int(port1), int(dom2), int(port2))
+ info.update(consinfo)
+ self._add_console(info.id, info)
+ return info
+
+ def _add_console(self, id, info):
+ self.console[id] = info
+ self.console_db[id] = info.sxpr()
+ self.sync_console(id)
+
+ def _delete_console(self, id):
+ if id in self.console:
+ del self.console[id]
+ if id in self.console_db:
+ del self.console_db[id]
+ self.db.delete(id)
+
+ def console_ls(self):
+ self.refresh()
+ return self.console.keys()
+
+ def consoles(self):
+ self.refresh()
+ return self.console.values()
+
+ def console_create(self, dom):
+ consinfo = daemon.console_create(dom)
+ info = self._new_console(consinfo)
+ return info
+
+ def console_get(self, id):
+ self.refresh()
+ return self.console.get(id)
+
+ def console_delete(self, id):
+ self._delete_console(id)
+
+ def console_disconnect(self, id):
+ id = int(id)
+ daemon.console_disconnect(id)
+
+def instance():
+ global inst
+ try:
+ inst
+ except:
+ inst = XendConsole()
+ return inst
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+import os
+import os.path
+import errno
+import dircache
+import time
+
+import sxp
+import XendRoot
+xroot = XendRoot.instance()
+
+class XendDB:
+ """Persistence for Xend. Stores data in files and directories.
+ """
+
+ def __init__(self, path=None):
+ self.dbpath = xroot.get_dbroot()
+ if path:
+ self.dbpath = os.path.join(self.dbpath, path)
+ pass
+
+ def filepath(self, path):
+ return os.path.join(self.dbpath, path)
+
+ def fetch(self, path):
+ fpath = self.filepath(path)
+ return self.fetchfile(fpath)
+
+ def fetchfile(self, fpath):
+ pin = sxp.Parser()
+ fin = file(fpath, "rb")
+ try:
+ while 1:
+ try:
+ buf = fin.read(1024)
+ except IOError, ex:
+ if ex.errno == errno.EINTR:
+ continue
+ else:
+ raise
+ pin.input(buf)
+ if buf == '':
+ pin.input_eof()
+ break
+ finally:
+ fin.close()
+ return pin.get_val()
+
+ def save(self, path, sxpr):
+ fpath = self.filepath(path)
+ return self.savefile(fpath, sxpr)
+
+ def savefile(self, fpath, sxpr):
+ fdir = os.path.dirname(fpath)
+ if not os.path.isdir(fdir):
+ os.makedirs(fdir)
+ fout = file(fpath, "wb+")
+ try:
+ t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
+ fout.write("# %s %s\n" % (fpath, t))
+ sxp.show(sxpr, out=fout)
+ finally:
+ fout.close()
+
+ def fetchall(self, path):
+ dpath = self.filepath(path)
+ d = {}
+ for k in dircache.listdir(dpath):
+ try:
+ v = self.fetchfile(os.path.join(dpath, k))
+ d[k] = v
+ except:
+ pass
+ return d
+
+ def saveall(self, path, d):
+ for (k, v) in d.items():
+ self.save(os.path.join(path, k), v)
+
+ def delete(self, path):
+ dpath = self.filepath(path)
+ os.unlink(dpath)
+
+ def ls(self, path):
+ dpath = self.filepath(path)
+ return dircache.listdir(dpath)
+
+
+
+
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+"""Handler for domain operations.
+ Nothing here is persistent (across reboots).
+ Needs to be persistent for one uptime.
+"""
+import sys
+
+from twisted.internet import defer
+
+import xen.ext.xc; xc = xen.ext.xc.new()
+
+import sxp
+import XendRoot
+xroot = XendRoot.instance()
+import XendDB
+import XendDomainInfo
+import XendConsole
+import EventServer
+
+from xen.xend.server import SrvDaemon
+xend = SrvDaemon.instance()
+
+eserver = EventServer.instance()
+
+__all__ = [ "XendDomain" ]
+
+class XendDomain:
+ """Index of all domains. Singleton.
+ """
+
+ dbpath = "domain"
+ domain = {}
+
+ def __init__(self):
+ self.xconsole = XendConsole.instance()
+ # Table of domain info indexed by domain id.
+ self.db = XendDB.XendDB(self.dbpath)
+ #self.domain = {}
+ self.domain_db = self.db.fetchall("")
+ if xroot.get_rebooted():
+ print 'XendDomain> rebooted: removing all domain info'
+ self.rm_all()
+ eserver.subscribe('xend.virq', self.onVirq)
+ self.initial_refresh()
+
+ def onVirq(self, event, val):
+ print 'XendDomain> virq', val
+ self.reap()
+
+ def rm_all(self):
+ """Remove all domain info. Used after reboot.
+ """
+ for (k, v) in self.domain_db.items():
+ self._delete_domain(k, notify=0)
+
+ def initial_refresh(self):
+ """Refresh initial domain info from domain_db.
+ """
+ print "initial_refresh>"
+ for d in self.domain_db.values(): print 'db dom=', d
+ domlist = xc.domain_getinfo()
+ for d in domlist: print 'xc dom=', d
+ doms = {}
+ for d in domlist:
+ domid = str(d['dom'])
+ doms[domid] = d
+ dlist = []
+ for config in self.domain_db.values():
+ domid = str(sxp.child_value(config, 'id'))
+ print "dom=", domid, "config=", config
+ if domid in doms:
+ print "dom=", domid, "new"
+ deferred = self._new_domain(config, doms[domid])
+ dlist.append(deferred)
+ else:
+ print "dom=", domid, "del"
+ self._delete_domain(domid)
+ deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
+ def cbok(val):
+ #print "doms:"
+ #for d in self.domain.values(): print 'dom', d
+ self.refresh()
+ print "XendDomain>initial_refresh> doms:"
+ for d in self.domain.values(): print 'dom', d
+ deferred.addCallback(cbok)
+
+ def sync(self):
+ """Sync domain db to disk.
+ """
+ self.db.saveall("", self.domain_db)
+
+ def sync_domain(self, dom):
+ """Sync info for a domain to disk.
+
+ dom domain id (string)
+ """
+ self.db.save(dom, self.domain_db[dom])
+
+ def close(self):
+ pass
+
+ def _new_domain(self, savedinfo, info):
+ """Create a domain entry from saved info.
+ """
+## console = None
+## kernel = None
+## id = sxp.child_value(info, 'id')
+## dom = int(id)
+## name = sxp.child_value(info, 'name')
+## memory = int(sxp.child_value(info, 'memory'))
+## consoleinfo = sxp.child(info, 'console')
+## if consoleinfo:
+## consoleid = sxp.child_value(consoleinfo, 'id')
+## console = self.xconsole.console_get(consoleid)
+## if dom and console is None:
+## # Try to connect a console.
+## console = self.xconsole.console_create(dom)
+## config = sxp.child(info, 'config')
+## if config:
+## image = sxp.child(info, 'image')
+## if image:
+## image = sxp.child0(image)
+## kernel = sxp.child_value(image, 'kernel')
+## dominfo = XendDomainInfo.XendDomainInfo(
+## config, dom, name, memory, kernel, console)
+ config = sxp.child_value(savedinfo, 'config')
+ deferred = XendDomainInfo.vm_recreate(config, info)
+ def fn(dominfo):
+ self.domain[dominfo.id] = dominfo
+ deferred.addCallback(fn)
+ return deferred
+
+ def _add_domain(self, id, info, notify=1):
+ self.domain[id] = info
+ self.domain_db[id] = info.sxpr()
+ self.sync_domain(id)
+ if notify: eserver.inject('xend.domain.created', id)
+
+ def _delete_domain(self, id, notify=1):
+ if id in self.domain:
+ if notify: eserver.inject('xend.domain.died', id)
+ del self.domain[id]
+ if id in self.domain_db:
+ del self.domain_db[id]
+ self.db.delete(id)
+
+ def reap(self):
+ """Go through the domains looking for ones that have crashed or stopped.
+ Tidy them up.
+ """
+ print 'XendDomain>reap>'
+ domlist = xc.domain_getinfo()
+ casualties = []
+ for d in domlist:
+ #print 'dom', d
+ dead = 0
+ dead = dead or (d['crashed'] or d['shutdown'])
+ dead = dead or (d['dying'] and
+ not(d['running'] or d['paused'] or d['blocked']))
+ if dead:
+ casualties.append(d)
+ for d in casualties:
+ id = str(d['dom'])
+ print 'XendDomain>reap> died id=', id, d
+ dominfo = self.domain.get(id)
+ if not dominfo: continue
+ dominfo.died()
+ self.domain_destroy(id, refresh=0)
+ print 'XendDomain>reap<'
+
+ def refresh(self):
+ """Refresh domain list from Xen.
+ """
+ domlist = xc.domain_getinfo()
+ # Index the domlist by id.
+ # Add entries for any domains we don't know about.
+ doms = {}
+ for d in domlist:
+ id = str(d['dom'])
+ doms[id] = d
+ if id not in self.domain:
+ config = None
+ #image = None
+ #newinfo = XendDomainInfo.XendDomainInfo(
+ # config, d['dom'], d['name'], d['mem_kb']/1024, image=image, info=d)
+ deferred = XendDomainInfo.vm_recreate(config, d)
+ def fn(dominfo):
+ self._add_domain(dominfo.id, dominfo)
+ deferred.addCallback(fn)
+ # Remove entries for domains that no longer exist.
+ for d in self.domain.values():
+ dominfo = doms.get(d.id)
+ if dominfo:
+ d.update(dominfo)
+ else:
+ self._delete_domain(d.id)
+ self.reap()
+
+ def refresh_domain(self, id):
+ dom = int(id)
+ dominfo = xc.domain_getinfo(dom, 1)
+ if dominfo == [] or dominfo[0]['dom'] != dom:
+ try:
+ self._delete_domain(id)
+ except:
+ print 'refresh_domain: error'
+ raise
+ pass
+ else:
+ d = self.domain.get(id)
+ if d:
+ d.update(dominfo[0])
+
+ def domain_ls(self):
+ # List domains.
+ # Update info from kernel first.
+ self.refresh()
+ return self.domain.keys()
+
+ def domains(self):
+ self.refresh()
+ return self.domain.values()
+
+ def domain_create(self, config):
+ # Create domain, log it.
+ deferred = XendDomainInfo.vm_create(config)
+ def fn(dominfo):
+ self._add_domain(dominfo.id, dominfo)
+ return dominfo
+ deferred.addCallback(fn)
+ return deferred
+
+ def domain_get(self, id):
+ id = str(id)
+ self.refresh_domain(id)
+ return self.domain.get(id)
+
+ def domain_unpause(self, id):
+ """(Re)start domain running.
+ """
+ dom = int(id)
+ eserver.inject('xend.domain.unpause', id)
+ return xc.domain_unpause(dom=dom)
+
+ def domain_pause(self, id):
+ """Pause domain execution.
+ """
+ dom = int(id)
+ eserver.inject('xend.domain.pause', id)
+ return xc.domain_pause(dom=dom)
+
+ def domain_shutdown(self, id, reason='poweroff'):
+ """Shutdown domain (nicely).
+ """
+ dom = int(id)
+ if dom <= 0:
+ return 0
+ eserver.inject('xend.domain.shutdown', [id, reason])
+ val = xend.domain_shutdown(dom, reason)
+ self.refresh()
+ return val
+
+ def domain_destroy(self, id, refresh=1):
+ """Terminate domain immediately.
+ """
+ dom = int(id)
+ if dom <= 0:
+ return 0
+ eserver.inject('xend.domain.destroy', id)
+ val = xc.domain_destroy(dom=dom)
+ if refresh: self.refresh()
+ return val
+
+ def domain_migrate(self, id, dst):
+ """Start domain migration.
+ """
+ # Need a cancel too?
+ pass
+
+ def domain_save(self, id, dst, progress=0):
+ """Save domain state to file, destroy domain.
+ """
+ dom = int(id)
+ dominfo = self.domain_get(id)
+ if not dominfo:
+ return -1
+ vmconfig = sxp.to_string(dominfo.sxpr())
+ self.domain_pause(id)
+ eserver.inject('xend.domain.save', id)
+ rc = xc.linux_save(dom=dom, state_file=dst, vmconfig=vmconfig, progress=progress)
+ if rc == 0:
+ self.domain_destroy(id)
+ return rc
+
+ def domain_restore(self, src, progress=0):
+ """Restore domain from file.
+ """
+ dominfo = XendDomainInfo.vm_restore(src, progress=progress)
+ self._add_domain(dominfo.id, dominfo)
+ return dominfo
+
+ #============================================================================
+ # Backward compatibility stuff from here on.
+
+ def domain_pincpu(self, dom, cpu):
+ dom = int(dom)
+ return xc.domain_pincpu(dom, cpu)
+
+ def domain_cpu_bvt_set(self, dom, mcuadv, warp, warpl, warpu):
+ dom = int(dom)
+ return xc.bvtsched_domain_set(dom=dom, mcuadv=mcuadv,
+ warp=warp, warpl=warpl, warpu=warpu)
+
+ def domain_cpu_bvt_get(self, dom):
+ dom = int(dom)
+ return xc.bvtsched_domain_get(dom)
+
+ def domain_cpu_atropos_set(self, dom, period, slice, latency, xtratime):
+ dom = int(dom)
+ return xc.atropos_domain_set(dom, period, slice, latency, xtratime)
+
+ def domain_cpu_atropos_get(self, dom):
+ dom = int(dom)
+ return xc.atropos_domain_get(dom)
+
+ def domain_vif_ls(self, dom):
+ dominfo = self.domain_get(dom)
+ if not dominfo: return None
+ devs = dominfo.get_devices('vif')
+ return range(0, len(devs))
+
+ def domain_vif_get(self, dom, vif):
+ dominfo = self.domain_get(dom)
+ if not dominfo: return None
+ return dominfo.get_device_by_index(vif)
+
+## def domain_vif_ip_add(self, dom, vif, ip):
+## dom = int(dom)
+## return xenctl.ip.setup_vfr_rules_for_vif(dom, vif, ip)
+
+ def domain_vbd_ls(self, dom):
+ dominfo = self.domain_get(dom)
+ if not dominfo: return []
+ devs = dominfo.get_devices('vbd')
+ return [ sxp.child_value(v, 'dev') for v in devs ]
+
+ def domain_vbd_get(self, dom, vbd):
+ dominfo = self.domain_get(dom)
+ if not dominfo: return None
+ devs = dominfo.get_devices('vbd')
+ for v in devs:
+ if sxp.child_value(v, 'dev') == vbd:
+ return v
+ return None
+
+ def domain_shadow_control(self, dom, op):
+ dom = int(dom)
+ return xc.shadow_control(dom, op)
+
+ #============================================================================
+
+def instance():
+ global inst
+ try:
+ inst
+ except:
+ inst = XendDomain()
+ return inst
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+"""Handler for persistent domain configs.
+
+"""
+
+import sxp
+import XendDB
+import XendDomain
+
+__all__ = [ "XendDomainConfig" ]
+
+class XendDomainConfig:
+
+ dbpath = 'config'
+
+ def __init__(self):
+ self.db = XendDB.XendDB(self.dbpath)
+
+ def domain_config_ls(self, path):
+ return self.db.ls(path)
+
+ def domain_config_create(self, path, sxpr):
+ self.db.save(path, sxpr)
+ pass
+
+ def domain_config_delete(self, path):
+ self.db.delete(path)
+
+ def domain_config_instance(self, path):
+ """Create a domain from a config.
+ """
+ config = self.db.fetch(path)
+ xd = XendDomain.instance()
+ newdom = xd.domain_create(config)
+ return newdom
+
+def instance():
+ global inst
+ try:
+ inst
+ except:
+ inst = XendDomainConfig()
+ return inst
--- /dev/null
+#!/usr/bin/python
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+"""Representation of a single domain.
+Includes support for domain construction, using
+open-ended configurations.
+
+Author: Mike Wray <mike.wray@hpl.hp.com>
+
+"""
+
+import string
+import re
+import sys
+import os
+
+from twisted.internet import defer
+
+import xen.ext.xc; xc = xen.ext.xc.new()
+import xen.util.ip
+
+import sxp
+
+import XendConsole
+xendConsole = XendConsole.instance()
+
+import server.SrvDaemon
+xend = server.SrvDaemon.instance()
+
+SIF_BLK_BE_DOMAIN = (1<<4)
+SIF_NET_BE_DOMAIN = (1<<5)
+
+def readlines(fd):
+ """Version of readlines safe against EINTR.
+ """
+ import errno
+
+ lines = []
+ while 1:
+ try:
+ line = fd.readline()
+ except IOError, ex:
+ if ex.errno == errno.EINTR:
+ continue
+ else:
+ raise
+ if line == '': break
+ lines.append(line)
+ return lines
+
+class VmError(ValueError):
+ """Vm construction error."""
+
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return self.value
+
+
+def blkdev_name_to_number(name):
+ """Take the given textual block-device name (e.g., '/dev/sda1',
+ 'hda') and return the device number used by the OS. """
+
+ if not re.match( '/dev/', name ):
+ name = '/dev/' + name
+
+ return os.stat(name).st_rdev
+
+def lookup_raw_partn(partition):
+ """Take the given block-device name (e.g., '/dev/sda1', 'hda')
+ and return a dictionary { device, start_sector,
+ nr_sectors, type }
+ device: Device number of the given partition
+ start_sector: Index of first sector of the partition
+ nr_sectors: Number of sectors comprising this partition
+ type: 'Disk' or identifying name for partition type
+ """
+
+ if not re.match( '/dev/', partition ):
+ partition = '/dev/' + partition
+
+ drive = re.split( '[0-9]', partition )[0]
+
+ if drive == partition:
+ fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' )
+ line = readline(fd)
+ if line:
+ return [ { 'device' : blkdev_name_to_number(drive),
+ 'start_sector' : long(0),
+ 'nr_sectors' : long(line) * 2,
+ 'type' : 'Disk' } ]
+ return None
+
+ # determine position on disk
+ fd = os.popen( '/sbin/sfdisk -d ' + drive + ' 2>/dev/null' )
+
+ #['/dev/sda3 : start= 16948575, size=16836120, Id=83, bootable\012']
+ lines = readlines(fd)
+ for line in lines:
+ m = re.search( '^' + partition + '\s*: start=\s*([0-9]+), ' +
+ 'size=\s*([0-9]+), Id=\s*(\S+).*$', line)
+ if m:
+ return [ { 'device' : blkdev_name_to_number(drive),
+ 'start_sector' : long(m.group(1)),
+ 'nr_sectors' : long(m.group(2)),
+ 'type' : m.group(3) } ]
+
+ return None
+
+def lookup_disk_uname(uname):
+ """Lookup a list of segments for a physical device.
+ uname [string]: name of the device in the format \'phy:dev\' for a physical device
+ returns [list of dicts]: list of extents that make up the named device
+ """
+ ( type, d_name ) = string.split( uname, ':' )
+
+ if type == "phy":
+ segments = lookup_raw_partn( d_name )
+ else:
+ segments = None
+ return segments
+
+def make_disk(dom, uname, dev, mode, recreate=0):
+ """Create a virtual disk device for a domain.
+
+ @returns Deferred
+ """
+ segments = lookup_disk_uname(uname)
+ if not segments:
+ raise VmError("vbd: Segments not found: uname=%s" % uname)
+ if len(segments) > 1:
+ raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname)
+ segment = segments[0]
+ vdev = blkdev_name_to_number(dev)
+ ctrl = xend.blkif_create(dom, recreate=recreate)
+
+ def fn(ctrl):
+ return xend.blkif_dev_create(dom, vdev, mode, segment, recreate=recreate)
+ ctrl.addCallback(fn)
+ return ctrl
+
+def make_vif(dom, vif, vmac, recreate=0):
+ """Create a virtual network device for a domain.
+
+
+ @returns Deferred
+ """
+ xend.netif_create(dom, recreate=recreate)
+ d = xend.netif_dev_create(dom, vif, vmac, recreate=recreate)
+ return d
+
+def vif_up(iplist):
+ """send an unsolicited ARP reply for all non link-local IP addresses.
+
+ iplist IP addresses
+ """
+
+ IP_NONLOCAL_BIND = '/proc/sys/net/ipv4/ip_nonlocal_bind'
+
+ def get_ip_nonlocal_bind():
+ return int(open(IP_NONLOCAL_BIND, 'r').read()[0])
+
+ def set_ip_nonlocal_bind(v):
+ print >> open(IP_NONLOCAL_BIND, 'w'), str(v)
+
+ def link_local(ip):
+ return xen.util.ip.check_subnet(ip, '169.254.0.0', '255.255.0.0')
+
+ def arping(ip, gw):
+ cmd = '/usr/sbin/arping -A -b -I eth0 -c 1 -s %s %s' % (ip, gw)
+ print cmd
+ os.system(cmd)
+
+ gateway = xen.util.ip.get_current_ipgw() or '255.255.255.255'
+ nlb = get_ip_nonlocal_bind()
+ if not nlb: set_ip_nonlocal_bind(1)
+ try:
+ for ip in iplist:
+ if not link_local(ip):
+ arping(ip, gateway)
+ finally:
+ if not nlb: set_ip_nonlocal_bind(0)
+
+config_handlers = {}
+
+def add_config_handler(name, h):
+ """Add a handler for a config field.
+
+ name field name
+ h handler: fn(vm, config, field, index)
+ """
+ config_handlers[name] = h
+
+def get_config_handler(name):
+ """Get a handler for a config field.
+
+ returns handler or None
+ """
+ return config_handlers.get(name)
+
+"""Table of handlers for virtual machine images.
+Indexed by image type.
+"""
+image_handlers = {}
+
+def add_image_handler(name, h):
+ """Add a handler for an image type
+ name image type
+ h handler: fn(config, name, memory, image)
+ """
+ image_handlers[name] = h
+
+def get_image_handler(name):
+ """Get the handler for an image type.
+ name image type
+
+ returns handler or None
+ """
+ return image_handlers.get(name)
+
+"""Table of handlers for devices.
+Indexed by device type.
+"""
+device_handlers = {}
+
+def add_device_handler(name, h):
+ """Add a handler for a device type.
+
+ name device type
+ h handler: fn(vm, dev)
+ """
+ device_handlers[name] = h
+
+def get_device_handler(name):
+ """Get the handler for a device type.
+
+ name device type
+
+ returns handler or None
+ """
+ return device_handlers.get(name)
+
+def vm_create(config):
+ """Create a VM from a configuration.
+ If a vm has been partially created and there is an error it
+ is destroyed.
+
+ config configuration
+
+ returns Deferred
+ raises VmError for invalid configuration
+ """
+ print 'vm_create>'
+ vm = XendDomainInfo()
+ return vm.construct(config)
+
+def vm_recreate(config, info):
+ """Create the VM object for an existing domain.
+ """
+ vm = XendDomainInfo()
+ vm.recreate = 1
+ vm.setdom(info['dom'])
+ vm.name = info['name']
+ vm.memory = info['mem_kb']/1024
+ if config:
+ d = vm.construct(config)
+ else:
+ d = defer.Deferred()
+ d.callback(vm)
+ return d
+
+def vm_restore(src, progress=0):
+ """Restore a VM from a disk image.
+
+ src saved state to restore
+ progress progress reporting flag
+ returns deferred
+ raises VmError for invalid configuration
+ """
+ vm = XendDomainInfo()
+ ostype = "linux" #todo Set from somewhere (store in the src?).
+ restorefn = getattr(xc, "%s_restore" % ostype)
+ d = restorefn(state_file=src, progress=progress)
+ dom = int(d['dom'])
+ if dom < 0:
+ raise VMError('restore failed')
+ vmconfig = sxp.from_string(d['vmconfig'])
+ vm.config = sxp.child_value(vmconfig, 'config')
+ deferred = vm.dom_configure(dom)
+ def vifs_cb(val, vm):
+ vif_up(vm.ipaddrs)
+ deferred.addCallback(vifs_cb, vm)
+ return deferred
+
+def dom_get(dom):
+ domlist = xc.domain_getinfo(dom=dom)
+ if domlist and dom == domlist[0]['dom']:
+ return domlist[0]
+ return None
+
+
+def append_deferred(dlist, v):
+ if isinstance(v, defer.Deferred):
+ dlist.append(v)
+
+def _vm_configure1(val, vm):
+ d = vm.create_devices()
+ print '_vm_configure1> made devices...'
+ def cbok(x):
+ print '_vm_configure1> cbok', x
+ return x
+ d.addCallback(cbok)
+ d.addCallback(_vm_configure2, vm)
+ print '_vm_configure1<'
+ return d
+
+def _vm_configure2(val, vm):
+ print '>callback _vm_configure2...'
+ d = vm.configure_fields()
+ def cbok(results):
+ print '_vm_configure2> cbok', results
+ return vm
+ def cberr(err):
+ print '_vm_configure2> cberr', err
+ vm.destroy()
+ return err
+ d.addCallback(cbok)
+ d.addErrback(cberr)
+ print '<_vm_configure2'
+ return d
+
+class XendDomainInfo:
+ """Virtual machine object."""
+
+ def __init__(self):
+ self.recreate = 0
+ self.config = None
+ self.id = None
+ self.dom = None
+ self.name = None
+ self.memory = None
+ self.image = None
+ self.ramdisk = None
+ self.cmdline = None
+ self.console = None
+ self.devices = {}
+ self.configs = []
+ self.info = None
+ self.ipaddrs = []
+ self.blkif_backend = 0
+ self.netif_backend = 0
+ #todo: state: running, suspended
+ self.state = 'running'
+ #todo: set to migrate info if migrating
+ self.migrate = None
+
+ def setdom(self, dom):
+ self.dom = int(dom)
+ self.id = str(dom)
+
+ def update(self, info):
+ """Update with info from xc.domain_getinfo().
+ """
+ self.info = info
+ self.memory = self.info['mem_kb'] / 1024
+
+ def __str__(self):
+ s = "domain"
+ s += " id=" + self.id
+ s += " name=" + self.name
+ s += " memory=" + str(self.memory)
+ if self.console:
+ s += " console=" + self.console.id
+ if self.image:
+ s += " image=" + self.image
+ s += ""
+ return s
+
+ __repr__ = __str__
+
+ def sxpr(self):
+ sxpr = ['domain',
+ ['id', self.id],
+ ['name', self.name],
+ ['memory', self.memory] ]
+ if self.info:
+ run = (self.info['running'] and 'r') or '-'
+ block = (self.info['blocked'] and 'b') or '-'
+ stop = (self.info['paused'] and 'p') or '-'
+ susp = (self.info['shutdown'] and 's') or '-'
+ crash = (self.info['crashed'] and 'c') or '-'
+ state = run + block + stop + susp + crash
+ sxpr.append(['state', state])
+ if self.info['shutdown']:
+ reasons = ["poweroff", "reboot", "suspend"]
+ reason = reasons[self.info['shutdown_reason']]
+ sxpr.append(['shutdown_reason', reason])
+ sxpr.append(['cpu', self.info['cpu']])
+ sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
+ if self.console:
+ sxpr.append(self.console.sxpr())
+ if self.config:
+ sxpr.append(['config', self.config])
+ return sxpr
+
+ def construct(self, config):
+ # todo - add support for scheduling params?
+ self.config = config
+ try:
+ self.name = sxp.child_value(config, 'name')
+ self.memory = int(sxp.child_value(config, 'memory', '128'))
+ self.configure_backends()
+ image = sxp.child_value(config, 'image')
+ image_name = sxp.name(image)
+ image_handler = get_image_handler(image_name)
+ if image_handler is None:
+ raise VmError('unknown image type: ' + image_name)
+ image_handler(self, image)
+ deferred = self.configure()
+ except StandardError, ex:
+ # Catch errors, cleanup and re-raise.
+ self.destroy()
+ raise
+ def cbok(x):
+ print 'vm_create> cbok', x
+ return x
+ deferred.addCallback(cbok)
+ print 'vm_create<'
+ return deferred
+
+ def config_devices(self, name):
+ """Get a list of the 'device' nodes of a given type from the config.
+
+ name device type
+ return list of device configs
+ """
+ devices = []
+ for d in sxp.children(self.config, 'device'):
+ dev = sxp.child0(d)
+ if dev is None: continue
+ if name == sxp.name(dev):
+ devices.append(dev)
+ return devices
+
+ def add_device(self, type, dev):
+ """Add a device to a virtual machine.
+
+ dev device to add
+ """
+ dl = self.devices.get(type, [])
+ dl.append(dev)
+ self.devices[type] = dl
+
+ def get_devices(self, type):
+ val = self.devices.get(type, [])
+ return val
+
+ def get_device_by_id(self, type, id):
+ """Get the device with the given id.
+
+ id device id
+
+ returns device or None
+ """
+ dl = self.get_devices(type)
+ for d in dl:
+ if d.getprop('id') == id:
+ return d
+ return None
+
+ def get_device_by_index(self, type, idx):
+ """Get the device with the given index.
+
+ idx device index
+
+ returns device or None
+ """
+ dl = self.get_devices(type)
+ if 0 <= idx < len(dl):
+ return dl[idx]
+ else:
+ return None
+
+ def add_config(self, val):
+ """Add configuration data to a virtual machine.
+
+ val data to add
+ """
+ self.configs.append(val)
+
+ def destroy(self):
+ if self.dom <= 0:
+ return 0
+ return xc.domain_destroy(dom=self.dom)
+
+ def died(self):
+ print 'died>', self.dom
+ self.release_devices()
+
+ def release_devices(self):
+ print 'release_devices>', self.dom
+ self.release_vifs()
+ self.release_vbds()
+ self.devices = {}
+
+ def release_vifs(self):
+ print 'release_vifs>', self.dom
+ if self.dom is None: return
+ ctrl = xend.netif_get(self.dom)
+ if ctrl:
+ ctrl.destroy()
+
+ def release_vbds(self):
+ print 'release_vbds>', self.dom
+ if self.dom is None: return
+ ctrl = xend.blkif_get(self.dom)
+ if ctrl:
+ ctrl.destroy()
+
+ def show(self):
+ """Print virtual machine info.
+ """
+ print "[VM dom=%d name=%s memory=%d" % (self.dom, self.name, self.memory)
+ print "image:"
+ sxp.show(self.image)
+ print
+ for dl in self.devices:
+ for dev in dl:
+ print "device:"
+ sxp.show(dev)
+ print
+ for val in self.configs:
+ print "config:"
+ sxp.show(val)
+ print
+ print "]"
+
+ def init_domain(self):
+ """Initialize the domain memory.
+ """
+ if self.recreate: return
+ memory = self.memory
+ name = self.name
+ cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
+ print 'init_domain>', memory, name, cpu
+ dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu)
+ if dom <= 0:
+ raise VmError('Creating domain failed: name=%s memory=%d'
+ % (name, memory))
+ self.setdom(dom)
+
+ def build_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n):
+ """Build the domain boot image.
+ """
+ if self.recreate: return
+ if len(cmdline) >= 256:
+ print 'Warning: kernel cmdline too long'
+ dom = self.dom
+ buildfn = getattr(xc, '%s_build' % ostype)
+ print 'build_domain>', ostype, dom, kernel, cmdline, ramdisk
+ flags = 0
+ if self.netif_backend: flags |= SIF_NET_BE_DOMAIN
+ if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN
+ err = buildfn(dom = dom,
+ image = kernel,
+ control_evtchn = self.console.port2,
+ cmdline = cmdline,
+ ramdisk = ramdisk,
+ flags = flags)
+ if err != 0:
+ raise VmError('Building domain failed: type=%s dom=%d err=%d'
+ % (ostype, dom, err))
+
+ def create_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n):
+ """Create a domain. Builds the image but does not configure it.
+
+ ostype OS type
+ kernel kernel image
+ ramdisk kernel ramdisk
+ cmdline kernel commandline
+ vifs_n number of network interfaces
+ """
+ print 'create_domain>', ostype, kernel
+ if not self.recreate:
+ if not os.path.isfile(kernel):
+ raise VmError('Kernel image does not exist: %s' % kernel)
+ if ramdisk and not os.path.isfile(ramdisk):
+ raise VMError('Kernel ramdisk does not exist: %s' % ramdisk)
+ print 'create-domain> init_domain...'
+ self.init_domain()
+ print 'create_domain>', 'dom=', self.dom
+ self.console = xendConsole.console_create(self.dom)
+ self.build_domain(ostype, kernel, ramdisk, cmdline, vifs_n)
+ self.image = kernel
+ self.ramdisk = ramdisk
+ self.cmdline = cmdline
+
+ def create_devices(self):
+ """Create the devices for a vm.
+
+ returns Deferred
+ raises VmError for invalid devices
+ """
+ print '>create_devices'
+ dlist = []
+ devices = sxp.children(self.config, 'device')
+ index = {}
+ for d in devices:
+ dev = sxp.child0(d)
+ if dev is None:
+ raise VmError('invalid device')
+ dev_name = sxp.name(dev)
+ dev_index = index.get(dev_name, 0)
+ dev_handler = get_device_handler(dev_name)
+ if dev_handler is None:
+ raise VmError('unknown device type: ' + dev_name)
+ v = dev_handler(self, dev, dev_index)
+ append_deferred(dlist, v)
+ index[dev_name] = dev_index + 1
+ deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
+ print '<create_devices'
+ return deferred
+
+ def configure_backends(self):
+ """Set configuration flags if the vm is a backend for netif of blkif.
+ """
+ for c in sxp.children(self.config, 'backend'):
+ name = sxp.name(sxp.child0(c))
+ if name == 'blkif':
+ self.blkif_backend = 1
+ elif name == 'netif':
+ self.netif_backend = 1
+ else:
+ raise VmError('invalid backend type:' + str(name))
+
+ def create_backends(self):
+ """Setup the netif and blkif backends.
+ """
+ if self.blkif_backend:
+ xend.blkif_set_control_domain(self.dom, recreate=self.recreate)
+ if self.netif_backend:
+ xend.netif_set_control_domain(self.dom, recreate=self.recreate)
+
+ def configure(self):
+ """Configure a vm.
+
+ vm virtual machine
+ config configuration
+
+ returns Deferred - calls callback with vm
+ """
+ if self.blkif_backend:
+ d = defer.Deferred()
+ d.callback(1)
+ else:
+ d = xend.blkif_create(self.dom, recreate=self.recreate)
+ d.addCallback(_vm_configure1, self)
+ return d
+
+ def dom_configure(self, dom):
+ """Configure a domain.
+
+ dom domain id
+ returns deferred
+ """
+ d = dom_get(dom)
+ if not d:
+ raise VMError("Domain not found: %d" % dom)
+ try:
+ self.setdom(dom)
+ self.name = d['name']
+ self.memory = d['memory']/1024
+ deferred = self.configure()
+ except StandardError, ex:
+ self.destroy()
+ raise
+ return deferred
+
+ def configure_fields(self):
+ dlist = []
+ index = {}
+ for field in sxp.children(self.config):
+ field_name = sxp.name(field)
+ field_index = index.get(field_name, 0)
+ field_handler = get_config_handler(field_name)
+ # Ignore unknown fields. Warn?
+ if field_handler:
+ v = field_handler(self, self.config, field, field_index)
+ append_deferred(dlist, v)
+ index[field_name] = field_index + 1
+ d = defer.DeferredList(dlist, fireOnOneErrback=1)
+ return d
+
+
+def vm_image_linux(vm, image):
+ """Create a VM for a linux image.
+
+ name vm name
+ memory vm memory
+ image image config
+
+ returns vm
+ """
+ kernel = sxp.child_value(image, "kernel")
+ cmdline = ""
+ ip = sxp.child_value(image, "ip", "dhcp")
+ if ip:
+ cmdline += " ip=" + ip
+ root = sxp.child_value(image, "root")
+ if root:
+ cmdline += " root=" + root
+ args = sxp.child_value(image, "args")
+ if args:
+ cmdline += " " + args
+ ramdisk = sxp.child_value(image, "ramdisk", '')
+ vifs = vm.config_devices("vif")
+ vm.create_domain("linux", kernel, ramdisk, cmdline, len(vifs))
+ return vm
+
+def vm_image_netbsd(vm, image):
+ """Create a VM for a bsd image.
+
+ name vm name
+ memory vm memory
+ image image config
+
+ returns vm
+ """
+ #todo: Same as for linux. Is that right? If so can unify them.
+ kernel = sxp.child_value(image, "kernel")
+ cmdline = ""
+ ip = sxp.child_value(image, "ip", "dhcp")
+ if ip:
+ cmdline += "ip=" + ip
+ root = sxp.child_value(image, "root")
+ if root:
+ cmdline += "root=" + root
+ args = sxp.child_value(image, "args")
+ if args:
+ cmdline += " " + args
+ ramdisk = sxp.child_value(image, "ramdisk")
+ vifs = vm.config_devices("vif")
+ vm.create_domain("netbsd", kernel, ramdisk, cmdline, len(vifs))
+ return vm
+
+
+def vm_dev_vif(vm, val, index):
+ """Create a virtual network interface (vif).
+
+ vm virtual machine
+ val vif config
+ index vif index
+ """
+ if vm.netif_backend:
+ raise VmError('vif: vif in netif backend domain')
+ vif = index #todo
+ vmac = sxp.child_value(val, "mac")
+ defer = make_vif(vm.dom, vif, vmac, vm.recreate)
+ def fn(id):
+ dev = xend.netif_dev(vm.dom, vif)
+ devid = sxp.attribute(val, 'id')
+ if devid:
+ dev.setprop('id', devid)
+ bridge = sxp.child_value(val, "bridge")
+ dev.up(bridge)
+ vm.add_device('vif', dev)
+ print 'vm_dev_vif> created', dev
+ return id
+ defer.addCallback(fn)
+ return defer
+
+def vm_dev_vbd(vm, val, index):
+ """Create a virtual block device (vbd).
+
+ vm virtual machine
+ val vbd config
+ index vbd index
+ """
+ if vm.blkif_backend:
+ raise VmError('vbd: vbd in blkif backend domain')
+ vdev = index
+ uname = sxp.child_value(val, 'uname')
+ if not uname:
+ raise VMError('vbd: Missing uname')
+ dev = sxp.child_value(val, 'dev')
+ if not dev:
+ raise VMError('vbd: Missing dev')
+ mode = sxp.child_value(val, 'mode', 'r')
+ defer = make_disk(vm.dom, uname, dev, mode, vm.recreate)
+ def fn(vbd):
+ dev = xend.blkif_dev(vm.dom, vdev)
+ vm.add_device('vbd', dev)
+ return vbd
+ defer.addCallback(fn)
+ return defer
+
+def parse_pci(val):
+ if isinstance(val, StringType):
+ radix = 10
+ if val.startswith('0x') or val.startswith('0X'):
+ radix = 16
+ v = int(val, radix)
+ else:
+ v = val
+ return v
+
+def vm_dev_pci(vm, val, index):
+ bus = sxp.child_value(val, 'bus')
+ if not bus:
+ raise VMError('pci: Missing bus')
+ dev = sxp.child_value(val, 'dev')
+ if not dev:
+ raise VMError('pci: Missing dev')
+ func = sxp.child_value(val, 'func')
+ if not func:
+ raise VMError('pci: Missing func')
+ try:
+ bus = parse_pci(bus)
+ dev = parse_pci(dev)
+ func = parse_pci(func)
+ except:
+ raise VMError('pci: invalid parameter')
+ rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev,
+ func=func, enable=1)
+ if rc < 0:
+ #todo non-fatal
+ raise VMError('pci: Failed to configure device: bus=%s dev=%s func=%s' %
+ (bus, dev, func))
+ return rc
+
+
+def vm_field_vfr(vm, config, val, index):
+ """Handle a vfr field in a config.
+
+ vm virtual machine
+ config vm config
+ val vfr field
+ """
+ # Get the rules and add them.
+ # (vfr (vif (id foo) (ip x.x.x.x)) ... )
+ list = sxp.children(val, 'vif')
+ ipaddrs = []
+ for v in list:
+ id = sxp.child_value(v, 'id')
+ if id is None:
+ raise VmError('vfr: missing vif id')
+ id = int(id)
+ dev = vm.get_device_by_index('vif', id)
+ if not dev:
+ raise VmError('vfr: invalid vif id %d' % id)
+ vif = sxp.child_value(dev, 'vif')
+ ip = sxp.child_value(v, 'ip')
+ if not ip:
+ raise VmError('vfr: missing ip address')
+ ipaddrs.append(ip);
+ # todo: Configure the ipaddrs.
+ vm.ipaddrs = ipaddrs
+
+def vnet_bridge(vnet, vmac, dom, idx):
+ """Add the device for the vif to the bridge for its vnet.
+ """
+ vif = "vif%d.%d" % (dom, idx)
+ try:
+ cmd = "(vif.conn (vif %s) (vnet %s) (vmac %s))" % (vif, vnet, vmac)
+ print "*** vnet_bridge>", cmd
+ out = file("/proc/vnet/policy", "wb")
+ out.write(cmd)
+ err = out.close()
+ print "vnet_bridge>", "err=", err
+ except IOError, ex:
+ print "vnet_bridge>", ex
+
+def vm_field_vnet(vm, config, val, index):
+ """Handle a vnet field in a config.
+
+ vm virtual machine
+ config vm config
+ val vnet field
+ index index
+ """
+ # Get the vif children. For each vif look up the vif device
+ # with the given id and configure its vnet.
+ # (vnet (vif (id foo) (vnet 2) (mac x:x:x:x:x:x)) ... )
+ vif_vnets = sxp.children(val, 'vif')
+ for v in vif_vnets:
+ id = sxp.child_value(v, 'id')
+ if id is None:
+ raise VmError('vnet: missing vif id')
+ dev = vm.get_device_by_id('vif', id)
+ #vnet = sxp.child_value(v, 'vnet', 1)
+ #mac = sxp.child_value(dev, 'mac')
+ #vif = sxp.child_value(dev, 'vif')
+ #vnet_bridge(vnet, mac, vm.dom, 0)
+ #vm.add_config([ 'vif.vnet', ['id', id], ['vnet', vnet], ['mac', mac]])
+
+# Register image handlers for linux and bsd.
+add_image_handler('linux', vm_image_linux)
+add_image_handler('netbsd', vm_image_netbsd)
+
+# Register device handlers for vifs and vbds.
+add_device_handler('vif', vm_dev_vif)
+add_device_handler('vbd', vm_dev_vbd)
+add_device_handler('pci', vm_dev_pci)
+
+# Register config handlers for vfr and vnet.
+add_config_handler('vfr', vm_field_vfr)
+add_config_handler('vnet', vm_field_vnet)
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+import sys
+import socket
+
+import sxp
+import XendDB
+import EventServer; eserver = EventServer.instance()
+
+class XendMigrateInfo:
+
+ # states: begin, active, failed, succeeded?
+
+ def __init__(self, id, dom, dst):
+ self.id = id
+ self.state = 'begin'
+ self.src_host = socket.gethostname()
+ self.src_dom = dom
+ self.dst_host = dst
+ self.dst_dom = None
+
+ def set_state(self, state):
+ self.state = state
+
+ def get_state(self):
+ return self.state
+
+ def sxpr(self):
+ sxpr = ['migrate', ['id', self.id], ['state', self.state] ]
+ sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ]
+ sxpr.append(sxpr_src)
+ sxpr_dst = ['dst', ['host', self.dst] ]
+ if self.dst_dom:
+ sxpr_dst.append(['domain', self.dst_dom])
+ sxpr.append(sxpr_dst)
+ return sxpr
+
+
+class XendMigrate:
+ # Represents migration in progress.
+ # Use log for indications of begin/end/errors?
+ # Need logging of: domain create/halt, migrate begin/end/fail
+ # Log via event server?
+
+ dbpath = "migrate"
+
+ def __init__(self):
+ self.db = XendDB.XendDB(self.dbpath)
+ self.migrate = {}
+ self.migrate_db = self.db.fetchall("")
+ self.id = 0
+
+ def nextid(self):
+ self.id += 1
+ return "%d" % self.id
+
+ def sync(self):
+ self.db.saveall("", self.migrate_db)
+
+ def sync_migrate(self, id):
+ self.db.save(id, self.migrate_db[id])
+
+ def close(self):
+ pass
+
+ def _add_migrate(self, id, info):
+ self.migrate[id] = info
+ self.migrate_db[id] = info.sxpr()
+ self.sync_migrate(id)
+ #eserver.inject('xend.migrate.begin', info.sxpr())
+
+ def _delete_migrate(self, id):
+ #eserver.inject('xend.migrate.end', id)
+ del self.migrate[id]
+ del self.migrate_db[id]
+ self.db.delete(id)
+
+ def migrate_ls(self):
+ return self.migrate.keys()
+
+ def migrates(self):
+ return self.migrate.values()
+
+ def migrate_get(self, id):
+ return self.migrate.get(id)
+
+ def migrate_begin(self, dom, dst):
+ # Check dom for existence, not migrating already.
+ # Create migrate info, tell xend to migrate it?
+ # - or fork migrate command ourselves?
+ # Subscribe to migrate notifications (for updating).
+ id = self.nextid()
+ info = XenMigrateInfo(id, dom, dst)
+ self._add_migrate(id, info)
+ return id
+
+def instance():
+ global inst
+ try:
+ inst
+ except:
+ inst = XendMigrate()
+ return inst
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+"""Handler for node operations.
+ Has some persistent state:
+ - logs
+ - notification urls
+
+"""
+
+import os
+import xen.ext.xc
+
+class XendNode:
+
+ def __init__(self):
+ self.xc = xen.ext.xc.new()
+
+ def shutdown(self):
+ return 0
+
+ def reboot(self):
+ return 0
+
+ def notify(self, uri):
+ return 0
+
+ def cpu_bvt_slice_set(self, slice):
+ ret = 0
+ #ret = self.xc.bvtsched_global_set(ctx_allow=slice)
+ return ret
+
+ def cpu_bvt_slice_get(self, slice):
+ ret = 0
+ #ret = self.xc.bvtsched_global_get()
+ return ret
+
+ def cpu_rrobin_slice_set(self, slice):
+ ret = 0
+ #ret = self.xc.rrobin_global_set(slice)
+ return ret
+
+ def info(self):
+ return self.nodeinfo() + self.physinfo()
+
+ def nodeinfo(self):
+ (sys, host, rel, ver, mch) = os.uname()
+ return [['system', sys],
+ ['host', host],
+ ['release', rel],
+ ['version', ver],
+ ['machine', mch]]
+
+ def physinfo(self):
+ pinfo = self.xc.physinfo()
+ info = [['cores', pinfo['cores']],
+ ['hyperthreads_per_core', pinfo['ht_per_core']],
+ ['cpu_mhz', pinfo['cpu_khz']/1000],
+ ['memory', pinfo['total_pages']/256],
+ ['free_memory', pinfo['free_pages']/256]]
+ return info
+
+
+
+def instance():
+ global inst
+ try:
+ inst
+ except:
+ inst = XendNode()
+ return inst
+
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+"""Xend root class.
+Creates the event server and handles configuration.
+"""
+
+import os
+import os.path
+import sys
+import EventServer
+
+# Initial create of the event server.
+eserver = EventServer.instance()
+
+import sxp
+
+def reboots():
+ """Get a list of system reboots from wtmp.
+ """
+ out = os.popen('/usr/bin/last reboot', 'r')
+ list = [ x.strip() for x in out if x.startswith('reboot') ]
+ return list
+
+def last_reboot():
+ """Get the last known system reboot.
+ """
+ l = reboots()
+ return (l and l[-1]) or None
+
+class XendRoot:
+ """Root of the management classes."""
+
+ lastboot_default = "/var/xen/lastboot"
+
+ """Default path to the root of the database."""
+ dbroot_default = "/var/xen/xend-db"
+
+ """Default path to the config file."""
+ config_default = "/etc/xen/xend-config.sxp"
+
+ """Environment variable used to override config_default."""
+ config_var = "XEND_CONFIG"
+
+ def __init__(self):
+ self.rebooted = 0
+ self.last_reboot = None
+ self.dbroot = None
+ self.config_path = None
+ self.config = None
+ self.configure()
+ self.check_lastboot()
+ eserver.subscribe('xend.*', self.event_handler)
+ #eserver.subscribe('xend.domain.created', self.event_handler)
+ #eserver.subscribe('xend.domain.died', self.event_handler)
+
+ def start(self):
+ eserver.inject('xend.start', self.rebooted)
+
+ def event_handler(self, event, val):
+ print >> sys.stderr, "EVENT>", event, val
+
+ def read_lastboot(self):
+ try:
+ val = file(self.lastboot, 'rb').readlines()[0]
+ except StandardError, ex:
+ print 'warning: Error reading', self.lastboot, ex
+ val = None
+ return val
+
+ def write_lastboot(self, val):
+ if not val: return
+ try:
+ fdir = os.path.dirname(self.lastboot)
+ if not os.path.isdir(fdir):
+ os.makedirs(fdir)
+ out = file(self.lastboot, 'wb+')
+ out.write(val)
+ out.close()
+ except IOError, ex:
+ print 'warning: Error writing', self.lastboot, ex
+ pass
+
+ def check_lastboot(self):
+ """Check if there has been a system reboot since we saved lastboot.
+ """
+ last_val = self.read_lastboot()
+ this_val = last_reboot()
+ if this_val == last_val:
+ self.rebooted = 0
+ else:
+ self.rebooted = 1
+ self.write_lastboot(this_val)
+ self.last_reboot = this_val
+
+ def get_last_reboot(self):
+ return self.last_reboot
+
+ def get_rebooted(self):
+ return self.rebooted
+
+ def configure(self):
+ self.set_config()
+ self.dbroot = self.get_config_value("dbroot", self.dbroot_default)
+ self.lastboot = self.get_config_value("lastboot", self.lastboot_default)
+
+ def get_dbroot(self):
+ """Get the path to the database root.
+ """
+ return self.dbroot
+
+ def set_config(self):
+ """If the config file exists, read it. If not, ignore it.
+
+ The config file is a sequence of sxp forms.
+ """
+ self.config_path = os.getenv(self.config_var, self.config_default)
+ if os.path.exists(self.config_path):
+ fin = file(self.config_path, 'rb')
+ try:
+ config = sxp.parse(fin)
+ config.insert(0, 'config')
+ self.config = config
+ finally:
+ fin.close()
+ else:
+ self.config = ['config']
+
+ def get_config(self, name=None):
+ """Get the configuration element with the given name, or
+ the whole configuration if no name is given.
+
+ name element name (optional)
+ returns config or none
+ """
+ if name is None:
+ val = self.config
+ else:
+ val = sxp.child(self.config, name)
+ return val
+
+ def get_config_value(self, name, val=None):
+ """Get the value of an atomic configuration element.
+
+ name element name
+ val default value (optional, defaults to None)
+ returns value
+ """
+ return sxp.child_value(self.config, name, val=val)
+
+def instance():
+ global inst
+ try:
+ inst
+ except:
+ inst = XendRoot()
+ return inst
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+"""Handler for vnet operations.
+"""
+
+import sxp
+import XendDB
+
+class XendVnet:
+ """Index of all vnets. Singleton.
+ """
+
+ dbpath = "vnet"
+
+ def __init__(self):
+ # Table of vnet info indexed by vnet id.
+ self.vnet = {}
+ self.db = XendDB.XendDB(self.dbpath)
+ self.vnet = self.db.fetchall("")
+
+ def vnet_ls(self):
+ """List all vnets.
+ """
+ return self.vnet.keys()
+
+ def vnets(self):
+ return self.vnet.values()
+
+ def vnet_get(self, id):
+ """Get a vnet.
+
+ id vnet id
+ """
+ return self.vnet.get(id)
+
+ def vnet_create(self, info):
+ """Create a vnet.
+
+ info config
+ """
+ self.vnet_configure(info)
+
+ def vnet_configure(self, info):
+ """Configure a vnet.
+ id vnet id
+ info config
+ """
+ # Need to configure for real.
+ # Only sync if succeeded - otherwise need to back out.
+ self.vnet[info.id] = info
+ self.db.save(info.id, info)
+
+ def vnet_delete(self, id):
+ """Delete a vnet.
+
+ id vnet id
+ """
+ # Need to delete for real. What if fails?
+ if id in self.vnet:
+ del self.vnet[id]
+ self.db.delete(id)
+
+def instance():
+ global inst
+ try:
+ inst
+ except:
+ inst = XendVnet()
+ return inst
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+"""Encoding for arguments to HTTP calls.
+ Uses the url-encoding with MIME type 'application/x-www-form-urlencoded'
+ if the data does not include files. Otherwise it uses the encoding with
+ MIME type 'multipart/form-data'. See the HTML4 spec for details.
+
+ """
+import sys
+import types
+from StringIO import StringIO
+
+import urllib
+import httplib
+import random
+import md5
+
+# Extract from HTML4 spec.
+## The following example illustrates "multipart/form-data"
+## encoding. Suppose we have the following form:
+
+## <FORM action="http://server.com/cgi/handle"
+## enctype="multipart/form-data"
+## method="post">
+## <P>
+## What is your name? <INPUT type="text" name="submit-name"><BR>
+## What files are you sending? <INPUT type="file" name="files"><BR>
+## <INPUT type="submit" value="Send"> <INPUT type="reset">
+## </FORM>
+
+## If the user enters "Larry" in the text input, and selects the text
+## file "file1.txt", the user agent might send back the following data:
+
+## Content-Type: multipart/form-data; boundary=AaB03x
+
+## --AaB03x
+## Content-Disposition: form-data; name="submit-name"
+
+## Larry
+## --AaB03x
+## Content-Disposition: form-data; name="files"; filename="file1.txt"
+## Content-Type: text/plain
+
+## ... contents of file1.txt ...
+## --AaB03x--
+
+## If the user selected a second (image) file "file2.gif", the user agent
+## might construct the parts as follows:
+
+## Content-Type: multipart/form-data; boundary=AaB03x
+
+## --AaB03x
+## Content-Disposition: form-data; name="submit-name"
+
+## Larry
+## --AaB03x
+## Content-Disposition: form-data; name="files"
+## Content-Type: multipart/mixed; boundary=BbC04y
+
+## --BbC04y
+## Content-Disposition: file; filename="file1.txt"
+## Content-Type: text/plain
+
+## ... contents of file1.txt ...
+## --BbC04y
+## Content-Disposition: file; filename="file2.gif"
+## Content-Type: image/gif
+## Content-Transfer-Encoding: binary
+
+## ...contents of file2.gif...
+## --BbC04y--
+## --AaB03x--
+
+__all__ = ['encode_data', 'encode_multipart', 'encode_form', 'mime_boundary' ]
+
+def data_values(d):
+ if isinstance(d, types.DictType):
+ return d.items()
+ else:
+ return d
+
+def encode_data(d):
+ """Encode some data for HTTP transport.
+ The encoding used is stored in 'Content-Type' in the headers.
+
+ d data - sequence of tuples or dictionary
+ returns a 2-tuple of the headers and the encoded data
+ """
+ val = ({}, None)
+ if d is None: return val
+ multipart = 0
+ for (k, v) in data_values(d):
+ if encode_isfile(v):
+ multipart = 1
+ break
+ if multipart:
+ val = encode_multipart(d)
+ else:
+ val = encode_form(d)
+ return val
+
+def encode_isfile(v):
+ if isinstance(v, types.FileType):
+ return 1
+ if hasattr(v, 'readlines'):
+ return 1
+ return 0
+
+def encode_multipart(d):
+ boundary = mime_boundary()
+ hdr = { 'Content-Type': 'multipart/form-data; boundary=' + boundary }
+ out = StringIO()
+ for (k,v) in data_values(d):
+ out.write('--')
+ out.write(boundary)
+ out.write('\r\n')
+ if encode_isfile(v):
+ out.write('Content-Disposition: form-data; name="')
+ out.write(k)
+ if hasattr(v, 'name'):
+ out.write('"; filename="')
+ out.write(v.name)
+ out.write('"\r\n')
+ out.write('Content-Type: application/octet-stream\r\n')
+ out.write('\r\n')
+ for l in v.readlines():
+ out.write(l)
+ else:
+ out.write('Content-Disposition: form-data; name="')
+ out.write(k)
+ out.write('"\r\n')
+ out.write('\r\n')
+ out.write(str(v))
+ out.write('\r\n')
+ out.write('--')
+ out.write(boundary)
+ out.write('--')
+ out.write('\r\n')
+ return (hdr, out.getvalue())
+
+def mime_boundary():
+ random.seed()
+ m = md5.new()
+ for i in range(0, 10):
+ c = chr(random.randint(1, 255))
+ m.update(c)
+ b = m.hexdigest()
+ return b[0:16]
+
+def encode_form(d):
+ hdr = { 'Content-Type': 'application/x-www-form-urlencoded' }
+ val = urllib.urlencode(d)
+ return (hdr, val)
+
+def main():
+ #d = {'a': 1, 'b': 'x y', 'c': file('conf.sxp') }
+ #d = {'a': 1, 'b': 'x y' }
+ d = [ ('a', 1), ('b', 'x y'), ('c', file('conf.sxp')) ]
+ #d = [ ('a', 1), ('b', 'x y')]
+ v = encode_data(d)
+ print v[0]
+ sys.stdout.write(v[1])
+ print
+
+if __name__ == "__main__":
+ main()
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+import cgi
+
+import os
+import sys
+import types
+import StringIO
+
+from twisted.internet import defer
+from twisted.internet import reactor
+from twisted.web import error
+from twisted.web import resource
+from twisted.web import server
+
+from xen.xend import sxp
+from xen.xend import PrettyPrint
+
+def uri_pathlist(p):
+ """Split a path into a list.
+ p path
+ return list of path elements
+ """
+ l = []
+ for x in p.split('/'):
+ if x == '': continue
+ l.append(x)
+ return l
+
+class SrvBase(resource.Resource):
+ """Base class for services.
+ """
+
+ def parse_form(self, req, method):
+ """Parse the data for a request, GET using the URL, POST using encoded data.
+ Posts should use enctype='multipart/form-data' in the <form> tag,
+ rather than 'application/x-www-form-urlencoded'. Only 'multipart/form-data'
+ handles file upload.
+
+ req request
+ returns a cgi.FieldStorage instance
+ """
+ env = {}
+ env['REQUEST_METHOD'] = method
+ if self.query:
+ env['QUERY_STRING'] = self.query
+ val = cgi.FieldStorage(fp=req.rfile, headers=req.headers, environ=env)
+ return val
+
+ def use_sxp(self, req):
+ """Determine whether to send an SXP response to a request.
+ Uses SXP if there is no User-Agent, no Accept, or application/sxp is in Accept.
+
+ req request
+ returns 1 for SXP, 0 otherwise
+ """
+ ok = 0
+ user_agent = req.getHeader('User-Agent')
+ accept = req.getHeader('Accept')
+ if (not user_agent) or (not accept) or (accept.find(sxp.mime_type) >= 0):
+ ok = 1
+ return ok
+
+ def get_op_method(self, op):
+ """Get the method for an operation.
+ For operation 'foo' looks for 'op_foo'.
+
+ op operation name
+ returns method or None
+ """
+ op_method_name = 'op_' + op
+ return getattr(self, op_method_name, None)
+
+ def perform(self, req):
+ """General operation handler for posted operations.
+ For operation 'foo' looks for a method op_foo and calls
+ it with op_foo(op, req). Replies with code 500 if op_foo
+ is not found.
+
+ The method must return a list when req.use_sxp is true
+ and an HTML string otherwise (or list).
+ Methods may also return a Deferred (for incomplete processing).
+
+ req request
+ """
+ op = req.args.get('op')
+ if op is None or len(op) != 1:
+ req.setResponseCode(404, "Invalid")
+ return ''
+ op = op[0]
+ op_method = self.get_op_method(op)
+ if op_method is None:
+ req.setResponseCode(501, "Not implemented")
+ req.setHeader("Content-Type", "text/plain")
+ req.write("Not implemented: " + op)
+ return ''
+ else:
+ val = op_method(op, req)
+ if isinstance(val, defer.Deferred):
+ val.addCallback(self._cb_perform, req, 1)
+ return server.NOT_DONE_YET
+ else:
+ self._cb_perform(val, req, 0)
+ return ''
+
+ def _cb_perform(self, val, req, dfr):
+ """Callback to complete the request.
+ May be called from a Deferred.
+ """
+ if isinstance(val, error.ErrorPage):
+ req.write(val.render(req))
+ elif self.use_sxp(req):
+ req.setHeader("Content-Type", sxp.mime_type)
+ sxp.show(val, req)
+ else:
+ req.write('<html><head></head><body>')
+ self.print_path(req)
+ if isinstance(val, types.ListType):
+ req.write('<code><pre>')
+ PrettyPrint.prettyprint(val, out=req)
+ req.write('</pre></code>')
+ else:
+ req.write(str(val))
+ req.write('</body></html>')
+ if dfr:
+ req.finish()
+
+ def print_path(self, req):
+ """Print the path with hyperlinks.
+ """
+ pathlist = [x for x in req.prepath if x != '' ]
+ s = "/"
+ req.write('<h1><a href="/">/</a>')
+ for x in pathlist:
+ s += x + "/"
+ req.write(' <a href="%s">%s</a>/' % (s, x))
+ req.write("</h1>")
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+from xen.xend import sxp
+from xen.xend import XendConsole
+from SrvDir import SrvDir
+
+class SrvConsole(SrvDir):
+ """An individual console.
+ """
+
+ def __init__(self, info):
+ SrvDir.__init__(self)
+ self.info = info
+ self.xc = XendConsole.instance()
+
+ def op_disconnect(self, op, req):
+ val = self.xc.console_disconnect(self.info.id)
+ return val
+
+ def render_POST(self, req):
+ return self.perform(req)
+
+ def render_GET(self, req):
+ if self.use_sxp(req):
+ req.setHeader("Content-Type", sxp.mime_type)
+ sxp.show(self.info.sxpr(), out=req)
+ else:
+ req.write('<html><head></head><body>')
+ self.print_path(req)
+ #self.ls()
+ req.write('<p>%s</p>' % self.info)
+ req.write('<p><a href="%s">Connect to domain %d</a></p>'
+ % (self.info.uri(), self.info.dom2))
+ self.form(req)
+ req.write('</body></html>')
+ return ''
+
+ def form(self, req):
+ req.write('<form method="post" action="%s">' % req.prePathURL())
+ if self.info.connection():
+ req.write('<input type="submit" name="op" value="disconnect">')
+ req.write('</form>')
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+from SrvDir import SrvDir
+from SrvConsole import SrvConsole
+from xen.xend import XendConsole
+from xen.xend import sxp
+
+class SrvConsoleDir(SrvDir):
+ """Console directory.
+ """
+
+ def __init__(self):
+ SrvDir.__init__(self)
+ self.xconsole = XendConsole.instance()
+
+ def console(self, x):
+ val = None
+ try:
+ info = self.xconsole.console_get(x)
+ val = SrvConsole(info)
+ except KeyError, ex:
+ print 'SrvConsoleDir>', ex
+ pass
+ return val
+
+ def get(self, x):
+ v = SrvDir.get(self, x)
+ if v is not None:
+ return v
+ v = self.console(x)
+ return v
+
+ def render_GET(self, req):
+ if self.use_sxp(req):
+ req.setHeader("Content-Type", sxp.mime_type)
+ self.ls_console(req, 1)
+ else:
+ req.write("<html><head></head><body>")
+ self.print_path(req)
+ self.ls(req)
+ self.ls_console(req)
+ #self.form(req.wfile)
+ req.write("</body></html>")
+ return ''
+
+ def ls_console(self, req, use_sxp=0):
+ url = req.prePathURL()
+ if not url.endswith('/'):
+ url += '/'
+ if use_sxp:
+ consoles = self.xconsole.console_ls()
+ sxp.show(consoles, out=req)
+ else:
+ consoles = self.xconsole.consoles()
+ consoles.sort(lambda x, y: cmp(x.id, y.id))
+ req.write('<ul>')
+ for c in consoles:
+ req.write('<li><a href="%s%s"> %s</a></li>' % (url, c.id, c))
+ req.write('</ul>')
--- /dev/null
+###########################################################
+## Xen controller daemon
+## Copyright (c) 2004, K A Fraser (University of Cambridge)
+## Copyright (C) 2004, Mike Wray <mike.wray@hp.com>
+###########################################################
+
+import os
+import os.path
+import signal
+import sys
+import threading
+import linecache
+import socket
+import pwd
+import re
+import StringIO
+
+from twisted.internet import pollreactor
+pollreactor.install()
+
+from twisted.internet import reactor
+from twisted.internet import protocol
+from twisted.internet import abstract
+from twisted.internet import defer
+
+from xen.ext import xu
+
+from xen.xend import sxp
+from xen.xend import PrettyPrint
+from xen.xend import EventServer
+eserver = EventServer.instance()
+
+from xen.xend.server import SrvServer
+
+import channel
+import blkif
+import netif
+import console
+import domain
+from params import *
+
+DEBUG = 1
+
+class MgmtProtocol(protocol.DatagramProtocol):
+ """Handler for the management socket (unix-domain).
+ """
+
+ def __init__(self, daemon):
+ #protocol.DatagramProtocol.__init__(self)
+ self.daemon = daemon
+
+ def write(self, data, addr):
+ return self.transport.write(data, addr)
+
+ def datagramReceived(self, data, addr):
+ if DEBUG: print 'datagramReceived> addr=', addr, 'data=', data
+ io = StringIO.StringIO(data)
+ try:
+ vals = sxp.parse(io)
+ res = self.dispatch(vals[0])
+ self.send_result(addr, res)
+ except SystemExit:
+ raise
+ except:
+ if DEBUG:
+ raise
+ else:
+ self.send_error(addr)
+
+ def send_reply(self, addr, sxpr):
+ io = StringIO.StringIO()
+ sxp.show(sxpr, out=io)
+ io.seek(0)
+ self.write(io.getvalue(), addr)
+
+ def send_result(self, addr, res):
+
+ def fn(res, self=self, addr=addr):
+ self.send_reply(addr, ['ok', res])
+
+ if isinstance(res, defer.Deferred):
+ res.addCallback(fn)
+ else:
+ fn(res)
+
+ def send_error(self, addr):
+ (extype, exval) = sys.exc_info()[:2]
+ self.send_reply(addr, ['err',
+ ['type', str(extype) ],
+ ['value', str(exval) ] ] )
+
+ def opname(self, name):
+ """Get the name of the method for an operation.
+ """
+ return 'op_' + name.replace('.', '_')
+
+ def operror(self, name, v):
+ """Default operation handler - signals an error.
+ """
+ raise NotImplementedError('Invalid operation: ' +name)
+
+ def dispatch(self, req):
+ """Dispatch a request to its handler.
+ """
+ op_name = sxp.name(req)
+ op_method_name = self.opname(op_name)
+ op_method = getattr(self, op_method_name, self.operror)
+ return op_method(op_name, req)
+
+ def op_console_create(self, name, req):
+ """Create a new control interface - console for a domain.
+ """
+ print name, req
+ dom = sxp.child_value(req, 'domain')
+ if not dom: raise ValueError('Missing domain')
+ dom = int(dom)
+ console_port = sxp.child_value(req, 'console_port')
+ if console_port:
+ console_port = int(console_port)
+ resp = self.daemon.console_create(dom, console_port)
+ print name, resp
+ return resp
+
+ def op_consoles(self, name, req):
+ """Get a list of the consoles.
+ """
+ return self.daemon.consoles()
+
+ def op_console_disconnect(self, name, req):
+ id = sxp.child_value(req, 'id')
+ if not id:
+ raise ValueError('Missing console id')
+ id = int(id)
+ console = self.daemon.get_console(id)
+ if not console:
+ raise ValueError('Invalid console id')
+ if console.conn:
+ console.conn.loseConnection()
+ return ['ok']
+
+ def op_blkifs(self, name, req):
+ pass
+
+ def op_blkif_devs(self, name, req):
+ pass
+
+ def op_blkif_create(self, name, req):
+ pass
+
+ def op_blkif_dev_create(self, name, req):
+ pass
+
+ def op_netifs(self, name, req):
+ pass
+
+ def op_netif_devs(self, name, req):
+ pass
+
+ def op_netif_create(self, name, req):
+ pass
+
+ def op_netif_dev_create(self, name, req):
+ pass
+
+class NotifierProtocol(protocol.Protocol):
+ """Asynchronous handler for i/o on the notifier (event channel).
+ """
+
+ def __init__(self, channelFactory):
+ self.channelFactory = channelFactory
+
+ def notificationReceived(self, idx, type):
+ #print 'NotifierProtocol>notificationReceived>', idx, type
+ channel = self.channelFactory.getChannel(idx)
+ if not channel:
+ return
+ #print 'NotifierProtocol>notificationReceived> channel', channel
+ channel.notificationReceived(type)
+
+ def connectionLost(self, reason=None):
+ pass
+
+ def doStart(self):
+ pass
+
+ def doStop(self):
+ pass
+
+ def startProtocol(self):
+ pass
+
+ def stopProtocol(self):
+ pass
+
+class NotifierPort(abstract.FileDescriptor):
+ """Transport class for the event channel.
+ """
+
+ def __init__(self, daemon, notifier, proto, reactor=None):
+ assert isinstance(proto, NotifierProtocol)
+ abstract.FileDescriptor.__init__(self, reactor)
+ self.daemon = daemon
+ self.notifier = notifier
+ self.protocol = proto
+
+ def startListening(self):
+ self._bindNotifier()
+ self._connectToProtocol()
+
+ def stopListening(self):
+ if self.connected:
+ result = self.d = defer.Deferred()
+ else:
+ result = None
+ self.loseConnection()
+ return result
+
+ def fileno(self):
+ return self.notifier.fileno()
+
+ def _bindNotifier(self):
+ self.connected = 1
+
+ def _connectToProtocol(self):
+ self.protocol.makeConnection(self)
+ self.startReading()
+
+ def loseConnection(self):
+ if self.connected:
+ self.stopReading()
+ self.disconnecting = 1
+ reactor.callLater(0, self.connectionLost)
+
+ def connectionLost(self, reason=None):
+ abstract.FileDescriptor.connectionLost(self, reason)
+ if hasattr(self, 'protocol'):
+ self.protocol.doStop()
+ self.connected = 0
+ #self.notifier.close() # Not implemented.
+ os.close(self.fileno())
+ del self.notifier
+ if hasattr(self, 'd'):
+ self.d.callback(None)
+ del self.d
+
+ def doRead(self):
+ #print 'NotifierPort>doRead>', self
+ count = 0
+ while 1:
+ #print 'NotifierPort>doRead>', count
+ notification = self.notifier.read()
+ if not notification:
+ break
+ (idx, type) = notification
+ self.protocol.notificationReceived(idx, type)
+ self.notifier.unmask(idx)
+ count += 1
+ #print 'NotifierPort>doRead<'
+
+class EventProtocol(protocol.Protocol):
+ """Asynchronous handler for a connected event socket.
+ """
+
+ def __init__(self, daemon):
+ #protocol.Protocol.__init__(self)
+ self.daemon = daemon
+ # Event queue.
+ self.queue = []
+ # Subscribed events.
+ self.events = []
+ self.parser = sxp.Parser()
+ self.pretty = 0
+
+ # For debugging subscribe to everything and make output pretty.
+ self.subscribe(['*'])
+ self.pretty = 1
+
+ def dataReceived(self, data):
+ try:
+ self.parser.input(data)
+ if self.parser.ready():
+ val = self.parser.get_val()
+ res = self.dispatch(val)
+ self.send_result(res)
+ if self.parser.at_eof():
+ self.loseConnection()
+ except SystemExit:
+ raise
+ except:
+ if DEBUG:
+ raise
+ else:
+ self.send_error()
+
+ def loseConnection(self):
+ if self.transport:
+ self.transport.loseConnection()
+ if self.connected:
+ reactor.callLater(0, self.connectionLost)
+
+ def connectionLost(self, reason=None):
+ self.unsubscribe()
+
+ def send_reply(self, sxpr):
+ io = StringIO.StringIO()
+ if self.pretty:
+ PrettyPrint.prettyprint(sxpr, out=io)
+ else:
+ sxp.show(sxpr, out=io)
+ print >> io
+ io.seek(0)
+ return self.transport.write(io.getvalue())
+
+ def send_result(self, res):
+ return self.send_reply(['ok', res])
+
+ def send_error(self):
+ (extype, exval) = sys.exc_info()[:2]
+ return self.send_reply(['err',
+ ['type', str(extype)],
+ ['value', str(exval)]])
+
+ def send_event(self, val):
+ return self.send_reply(['event', val[0], val[1]])
+
+ def unsubscribe(self):
+ for event in self.events:
+ eserver.unsubscribe(event, self.queue_event)
+
+ def subscribe(self, events):
+ self.unsubscribe()
+ for event in events:
+ eserver.subscribe(event, self.queue_event)
+ self.events = events
+
+ def queue_event(self, name, v):
+ # Despite the name we dont' queue the event here.
+ # We send it because the transport will queue it.
+ self.send_event([name, v])
+
+ def opname(self, name):
+ return 'op_' + name.replace('.', '_')
+
+ def operror(self, name, req):
+ raise NotImplementedError('Invalid operation: ' +name)
+
+ def dispatch(self, req):
+ op_name = sxp.name(req)
+ op_method_name = self.opname(op_name)
+ op_method = getattr(self, op_method_name, self.operror)
+ return op_method(op_name, req)
+
+ def op_help(self, name, req):
+ def nameop(x):
+ if x.startswith('op_'):
+ return x[3:].replace('_', '.')
+ else:
+ return x
+
+ l = [ nameop(k) for k in dir(self) if k.startswith('op_') ]
+ return l
+
+ def op_quit(self, name, req):
+ self.loseConnection()
+
+ def op_exit(self, name, req):
+ sys.exit(0)
+
+ def op_pretty(self, name, req):
+ self.pretty = 1
+ return ['ok']
+
+ def op_console_disconnect(self, name, req):
+ id = sxp.child_value(req, 'id')
+ if not id:
+ raise ValueError('Missing console id')
+ self.daemon.console_disconnect(id)
+ return ['ok']
+
+ def op_info(self, name, req):
+ val = ['info']
+ val += self.daemon.consoles()
+ val += self.daemon.blkifs()
+ val += self.daemon.netifs()
+ return val
+
+ def op_sys_subscribe(self, name, v):
+ # (sys.subscribe event*)
+ # Subscribe to the events:
+ self.subscribe(v[1:])
+ return ['ok']
+
+ def op_sys_inject(self, name, v):
+ # (sys.inject event)
+ event = v[1]
+ eserver.inject(sxp.name(event), event)
+ return ['ok']
+
+
+class EventFactory(protocol.Factory):
+ """Asynchronous handler for the event server socket.
+ """
+ protocol = EventProtocol
+ service = None
+
+ def __init__(self, daemon):
+ #protocol.Factory.__init__(self)
+ self.daemon = daemon
+
+ def buildProtocol(self, addr):
+ proto = self.protocol(self.daemon)
+ proto.factory = self
+ return proto
+
+class VirqClient:
+ def __init__(self, daemon):
+ self.daemon = daemon
+
+ def virqReceived(self, virq):
+ print 'VirqClient.virqReceived>', virq
+ eserver.inject('xend.virq', virq)
+
+ def lostChannel(self, channel):
+ print 'VirqClient.lostChannel>', channel
+
+class Daemon:
+ """The xend daemon.
+ """
+ def __init__(self):
+ self.shutdown = 0
+
+ def daemon_pids(self):
+ pids = []
+ pidex = '(?P<pid>\d+)'
+ pythonex = '(?P<python>\S*python\S*)'
+ cmdex = '(?P<cmd>.*)'
+ procre = re.compile('^\s*' + pidex + '\s*' + pythonex + '\s*' + cmdex + '$')
+ xendre = re.compile('^/usr/sbin/xend\s*(start|restart)\s*.*$')
+ procs = os.popen('ps -e -o pid,args 2>/dev/null')
+ for proc in procs:
+ pm = procre.match(proc)
+ if not pm: continue
+ xm = xendre.match(pm.group('cmd'))
+ if not xm: continue
+ #print 'pid=', pm.group('pid'), 'cmd=', pm.group('cmd')
+ pids.append(int(pm.group('pid')))
+ return pids
+
+ def new_cleanup(self, kill=0):
+ err = 0
+ pids = self.daemon_pids()
+ if kill:
+ for pid in pids:
+ print "Killing daemon pid=%d" % pid
+ os.kill(pid, signal.SIGHUP)
+ elif pids:
+ err = 1
+ print "Daemon already running: ", pids
+ return err
+
+ def cleanup(self, kill=False):
+ # No cleanup to do if PID_FILE is empty.
+ if not os.path.isfile(PID_FILE) or not os.path.getsize(PID_FILE):
+ return 0
+ # Read the pid of the previous invocation and search active process list.
+ pid = open(PID_FILE, 'r').read()
+ lines = os.popen('ps ' + pid + ' 2>/dev/null').readlines()
+ for line in lines:
+ if re.search('^ *' + pid + '.+xend', line):
+ if not kill:
+ print "Daemon is already running (pid %d)" % int(pid)
+ return 1
+ # Old daemon is still active: terminate it.
+ os.kill(int(pid), 1)
+ # Delete the stale PID_FILE.
+ os.remove(PID_FILE)
+ return 0
+
+ def install_child_reaper(self):
+ #signal.signal(signal.SIGCHLD, self.onSIGCHLD)
+ # Ensure that zombie children are automatically reaped.
+ xu.autoreap()
+
+ def onSIGCHLD(self, signum, frame):
+ code = 1
+ while code > 0:
+ code = os.waitpid(-1, os.WNOHANG)
+
+ def start(self,trace=0):
+ if self.cleanup(kill=False):
+ return 1
+
+ # Detach from TTY.
+ if not DEBUG:
+ os.setsid()
+
+ if self.set_user():
+ return 1
+
+ self.install_child_reaper()
+
+ # Fork -- parent writes PID_FILE and exits.
+ pid = os.fork()
+ if pid:
+ # Parent
+ pidfile = open(PID_FILE, 'w')
+ pidfile.write(str(pid))
+ pidfile.close()
+ return 0
+ # Child
+ logfile = self.open_logfile()
+ self.redirect_output(logfile)
+ if trace:
+ self.tracefile = open('/var/log/xend.trace', 'w+', 1)
+ self.traceindent = 0
+ sys.settrace(self.trace)
+ try:
+ threading.settrace(self.trace) # Only in Python >= 2.3
+ except:
+ pass
+ self.run()
+ return 0
+
+ def print_trace(self,str):
+ for i in range(self.traceindent):
+ self.tracefile.write(" ")
+ self.tracefile.write(str)
+
+ def trace(self, frame, event, arg):
+ if event == 'call':
+ code = frame.f_code
+ filename = code.co_filename
+ m = re.search('.*xenmgr/(.*)', code.co_filename)
+ if not m:
+ return None
+ modulename = m.group(1)
+ if re.search('sxp.py', modulename):
+ return None
+ self.traceindent += 1
+ self.print_trace("++++ %s:%s\n"
+ % (modulename, code.co_name))
+ elif event == 'line':
+ filename = frame.f_code.co_filename
+ lineno = frame.f_lineno
+ self.print_trace("%4d %s" %
+ (lineno, linecache.getline(filename, lineno)))
+ elif event == 'return':
+ code = frame.f_code
+ filename = code.co_filename
+ m = re.search('.*xenmgr/(.*)', code.co_filename)
+ if not m:
+ return None
+ modulename = m.group(1)
+ self.print_trace("---- %s:%s\n"
+ % (modulename, code.co_name))
+ self.traceindent -= 1
+ elif event == 'exception':
+ pass
+ return self.trace
+
+ def open_logfile(self):
+ if not os.path.exists(CONTROL_DIR):
+ os.makedirs(CONTROL_DIR)
+
+ # Open log file. Truncate it if non-empty, and request line buffering.
+ if os.path.isfile(LOG_FILE):
+ os.rename(LOG_FILE, LOG_FILE+'.old')
+ logfile = open(LOG_FILE, 'w+', 1)
+ return logfile
+
+ def set_user(self):
+ # Set the UID.
+ try:
+ os.setuid(pwd.getpwnam(USER)[2])
+ return 0
+ except KeyError, error:
+ print "Error: no such user '%s'" % USER
+ return 1
+
+ def redirect_output(self, logfile):
+ if DEBUG: return
+ # Close down standard file handles
+ try:
+ os.close(0) # stdin
+ os.close(1) # stdout
+ os.close(2) # stderr
+ except:
+ pass
+ # Redirect output to log file.
+ sys.stdout = sys.stderr = logfile
+
+ def stop(self):
+ return self.cleanup(kill=True)
+
+ def run(self):
+ self.createFactories()
+ self.listenMgmt()
+ self.listenEvent()
+ self.listenNotifier()
+ self.listenVirq()
+ SrvServer.create(bridge=1)
+ reactor.run()
+
+ def createFactories(self):
+ self.channelF = channel.channelFactory()
+ self.domainCF = domain.DomainControllerFactory()
+ self.blkifCF = blkif.BlkifControllerFactory()
+ self.netifCF = netif.NetifControllerFactory()
+ self.consoleCF = console.ConsoleControllerFactory()
+
+ def listenMgmt(self):
+ protocol = MgmtProtocol(self)
+ s = os.path.join(CONTROL_DIR, MGMT_SOCK)
+ if os.path.exists(s):
+ os.unlink(s)
+ return reactor.listenUNIXDatagram(s, protocol)
+
+ def listenEvent(self):
+ protocol = EventFactory(self)
+ return reactor.listenTCP(EVENT_PORT, protocol)
+
+ def listenNotifier(self):
+ protocol = NotifierProtocol(self.channelF)
+ p = NotifierPort(self, self.channelF.notifier, protocol, reactor)
+ p.startListening()
+ return p
+
+ def listenVirq(self):
+ virqChan = self.channelF.virqChannel(channel.VIRQ_DOM_EXC)
+ virqChan.registerClient(VirqClient(self))
+
+ def exit(self):
+ reactor.diconnectAll()
+ sys.exit(0)
+
+ def blkif_set_control_domain(self, dom, recreate=0):
+ """Set the block device backend control domain.
+ """
+ return self.blkifCF.setControlDomain(dom, recreate=recreate)
+
+ def blkif_get_control_domain(self, dom):
+ """Get the block device backend control domain.
+ """
+ return self.blkifCF.getControlDomain()
+
+ def blkif_create(self, dom, recreate=0):
+ """Create a block device interface controller.
+
+ Returns Deferred
+ """
+ d = self.blkifCF.createInstance(dom, recreate=recreate)
+ return d
+
+ def blkifs(self):
+ return [ x.sxpr() for x in self.blkifCF.getInstances() ]
+
+ def blkif_get(self, dom):
+ return self.blkifCF.getInstanceByDom(dom)
+
+ def blkif_dev(self, dom, vdev):
+ return self.blkifCF.getDomainDevice(dom, vdev)
+
+ def blkif_dev_create(self, dom, vdev, mode, segment, recreate=0):
+ """Create a block device.
+
+ Returns Deferred
+ """
+ ctrl = self.blkifCF.getInstanceByDom(dom)
+ if not ctrl:
+ raise ValueError('No blkif controller: %d' % dom)
+ print 'blkif_dev_create>', dom, vdev, mode, segment
+ d = ctrl.attachDevice(vdev, mode, segment, recreate=recreate)
+ return d
+
+ def netif_set_control_domain(self, dom, recreate=0):
+ """Set the network interface backend control domain.
+ """
+ return self.netifCF.setControlDomain(dom, recreate=recreate)
+
+ def netif_get_control_domain(self, dom):
+ """Get the network interface backend control domain.
+ """
+ return self.netifCF.getControlDomain()
+
+ def netif_create(self, dom, recreate=0):
+ """Create a network interface controller.
+
+ """
+ return self.netifCF.createInstance(dom, recreate=recreate)
+
+ def netifs(self):
+ return [ x.sxpr() for x in self.netifCF.getInstances() ]
+
+ def netif_get(self, dom):
+ return self.netifCF.getInstanceByDom(dom)
+
+ def netif_dev_create(self, dom, vif, vmac, recreate=0):
+ """Create a network device.
+
+ todo
+ """
+ ctrl = self.netifCF.getInstanceByDom(dom)
+ if not ctrl:
+ raise ValueError('No netif controller: %d' % dom)
+ d = ctrl.attachDevice(vif, vmac, recreate=recreate)
+ return d
+
+ def netif_dev(self, dom, vif):
+ return self.netifCF.getDomainDevice(dom, vif)
+
+ def console_create(self, dom, console_port=None):
+ """Create a console for a domain.
+ """
+ console = self.consoleCF.getInstanceByDom(dom)
+ if console is None:
+ console = self.consoleCF.createInstance(dom, console_port)
+ return console.sxpr()
+
+ def consoles(self):
+ return [ c.sxpr() for c in self.consoleCF.getInstances() ]
+
+ def get_console(self, id):
+ return self.consoleCF.getInstance(id)
+
+ def get_domain_console(self, dom):
+ return self.consoleCF.getInstanceByDom(dom)
+
+ def console_disconnect(self, id):
+ """Disconnect any connected console client.
+ """
+ console = self.get_console(id)
+ if not console:
+ raise ValueError('Invalid console id')
+ console.disconnect()
+
+ def domain_shutdown(self, dom, reason):
+ """Shutdown a domain.
+ """
+ ctrl = self.domainCF.getInstanceByDom(dom)
+ if not ctrl:
+ raise ValueError('No domain controller: %d' % dom)
+ ctrl.shutdown(reason)
+ return 0
+
+def instance():
+ global inst
+ try:
+ inst
+ except:
+ inst = Daemon()
+ return inst
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+from SrvDir import SrvDir
+
+class SrvDeviceDir(SrvDir):
+ """Device directory.
+ """
+
+ pass
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+from twisted.web import error
+from xen.xend import sxp
+from SrvBase import SrvBase
+
+class SrvConstructor:
+ """Delayed constructor for sub-servers.
+ Does not import the sub-server class or create the object until needed.
+ """
+
+ def __init__(self, klass):
+ """Create a constructor. It is assumed that the class
+ should be imported as 'import klass from klass'.
+
+ klass name of its class
+ """
+ self.klass = klass
+ self.obj = None
+
+ def getobj(self):
+ """Get the sub-server object, importing its class and instantiating it if
+ necessary.
+ """
+ if not self.obj:
+ exec 'from %s import %s' % (self.klass, self.klass)
+ klassobj = eval(self.klass)
+ self.obj = klassobj()
+ return self.obj
+
+class SrvDir(SrvBase):
+ """Base class for directory servlets.
+ """
+ isLeaf = False
+
+ def __init__(self):
+ SrvBase.__init__(self)
+ self.table = {}
+ self.order = []
+
+ def getChild(self, x, req):
+ if x == '': return self
+ val = self.get(x)
+ if val is None:
+ return error.NoResource('Not found')
+ else:
+ return val
+
+ def get(self, x):
+ val = self.table.get(x)
+ if val is not None:
+ val = val.getobj()
+ return val
+
+ def add(self, x, xclass = None):
+ if xclass is None:
+ xclass = 'SrvDir'
+ self.table[x] = SrvConstructor(xclass)
+ self.order.append(x)
+
+ def render_GET(self, req):
+ if self.use_sxp(req):
+ req.setHeader("Content-type", sxp.mime_type)
+ self.ls(req, 1)
+ else:
+ req.write('<html><head></head><body>')
+ self.print_path(req)
+ self.ls(req)
+ self.form(req)
+ req.write('</body></html>')
+ return ''
+
+ def ls(self, req, use_sxp=0):
+ url = req.prePathURL()
+ if not url.endswith('/'):
+ url += '/'
+ if use_sxp:
+ req.write('(ls ')
+ for k in self.order:
+ req.write(' ' + k)
+ req.write(')')
+ else:
+ req.write('<ul>')
+ for k in self.order:
+ v = self.get(k)
+ req.write('<li><a href="%s%s">%s</a></li>'
+ % (url, k, k))
+ req.write('</ul>')
+
+ def form(self, req):
+ pass
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+from xen.xend import sxp
+from xen.xend import XendDomain
+from xen.xend import XendConsole
+from xen.xend import PrettyPrint
+from xen.xend.Args import FormFn
+
+from SrvDir import SrvDir
+
+class SrvDomain(SrvDir):
+ """Service managing a single domain.
+ """
+
+ def __init__(self, dom):
+ SrvDir.__init__(self)
+ self.dom = dom
+ self.xd = XendDomain.instance()
+ self.xconsole = XendConsole.instance()
+
+ def op_unpause(self, op, req):
+ val = self.xd.domain_unpause(self.dom.id)
+ return val
+
+ def op_pause(self, op, req):
+ val = self.xd.domain_pause(self.dom.id)
+ return val
+
+ def op_shutdown(self, op, req):
+ val = self.xd.domain_shutdown(self.dom.id)
+ req.setResponseCode(202)
+ req.setHeader("Location", "%s/.." % req.prePathURL())
+ return val
+
+ def op_destroy(self, op, req):
+ val = self.xd.domain_destroy(self.dom.id)
+ req.setHeader("Location", "%s/.." % req.prePathURL())
+ return val
+
+ def op_save(self, op, req):
+ fn = FormFn(self.xd.domain_save,
+ [['dom', 'int'],
+ ['file', 'str']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_migrate(self, op, req):
+ fn = FormFn(self.xd.domain_migrate,
+ [['dom', 'int'],
+ ['destination', 'str']])
+ val = fn(req.args, {'dom': self.dom.id})
+ val = 0 # Some migrate id.
+ req.setResponseCode(202)
+ #req.send_header("Location", "%s/.." % self.path) # Some migrate url.
+ return val
+
+ def op_pincpu(self, op, req):
+ fn = FormFn(self.xd.domain_pincpu,
+ [['dom', 'int'],
+ ['cpu', 'int']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_cpu_bvt_set(self, op, req):
+ fn = FormFn(self.xd.domain_cpu_bvt_set,
+ [['dom', 'int'],
+ ['mcuadv', 'int'],
+ ['warp', 'int'],
+ ['warpl', 'int'],
+ ['warpu', 'int']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_cpu_atropos_set(self, op, req):
+ fn = FormFn(self.xd.domain_cpu_atropos_set,
+ [['dom', 'int'],
+ ['period', 'int'],
+ ['slice', 'int'],
+ ['latency', 'int'],
+ ['xtratime', 'int']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_vifs(self, op, req):
+ return self.xd.domain_vif_ls(self.dom.id)
+
+ def op_vif(self, op, req):
+ fn = FormFn(self.xd.domain_vif_get,
+ [['dom', 'int'],
+ ['vif', 'int']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_vif_stats(self, op, req):
+ #todo
+ fn = FormFn(self.xd.domain_vif_stats,
+ [['dom', 'int'],
+ ['vif', 'int']])
+ #val = fn(req.args, {'dom': self.dom.id})
+ val = 999
+ #return val
+ return val
+
+ def op_vif_ip_add(self, op, req):
+ fn = FormFn(self.xd.domain_vif_ip_add,
+ [['dom', 'int'],
+ ['vif', 'int'],
+ ['ip', 'str']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_vif_scheduler_set(self, op, req):
+ fn = FormFn(self.xd.domain_vif_scheduler_set,
+ [['dom', 'int'],
+ ['vif', 'int'],
+ ['bytes', 'int'],
+ ['usecs', 'int']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_vif_scheduler_get(self, op, req):
+ fn = FormFn(self.xd.domain_vif_scheduler_set,
+ [['dom', 'int'],
+ ['vif', 'int']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_vbds(self, op, req):
+ return self.xd.domain_vbd_ls(self.dom.id)
+
+ def op_vbd(self, op, req):
+ fn = FormFn(self.xd.domain_vbd_get,
+ [['dom', 'int'],
+ ['vbd', 'int']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_vbd_add(self, op, req):
+ fn = FormFn(self.xd.domain_vbd_add,
+ [['dom', 'int'],
+ ['uname', 'str'],
+ ['dev', 'str'],
+ ['mode', 'str']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_vbd_remove(self, op, req):
+ fn = FormFn(self.xd.domain_vbd_remove,
+ [['dom', 'int'],
+ ['dev', 'str']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def render_POST(self, req):
+ return self.perform(req)
+
+ def render_GET(self, req):
+ op = req.args.get('op')
+ if op and op[0] in ['vifs', 'vif', 'vif_stats', 'vbds', 'vbd']:
+ return self.perform(req)
+ if self.use_sxp(req):
+ req.setHeader("Content-Type", sxp.mime_type)
+ sxp.show(self.dom.sxpr(), out=req)
+ else:
+ req.write('<html><head></head><body>')
+ self.print_path(req)
+ #self.ls()
+ req.write('<p>%s</p>' % self.dom)
+ if self.dom.console:
+ cinfo = self.dom.console
+ cid = cinfo.id
+ #todo: Local xref: need to know server prefix.
+ req.write('<p><a href="/xend/console/%s">Console %s</a></p>'
+ % (cid, cid))
+ req.write('<p><a href="%s">Connect to console</a></p>'
+ % cinfo.uri())
+ if self.dom.config:
+ req.write("<code><pre>")
+ PrettyPrint.prettyprint(self.dom.config, out=req)
+ req.write("</pre></code>")
+ req.write('<a href="%s?op=vif_stats&vif=0">vif 0 stats</a>'
+ % req.prePathURL())
+ self.form(req)
+ req.write('</body></html>')
+ return ''
+
+ def form(self, req):
+ req.write('<form method="post" action="%s">' % req.prePathURL())
+ req.write('<input type="submit" name="op" value="unpause">')
+ req.write('<input type="submit" name="op" value="pause">')
+ req.write('<input type="submit" name="op" value="shutdown">')
+ req.write('<input type="submit" name="op" value="destroy">')
+ req.write('<br><input type="submit" name="op" value="migrate">')
+ req.write('To: <input type="text" name="destination">')
+ req.write('</form>')
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+from StringIO import StringIO
+
+from twisted.protocols import http
+from twisted.web import error
+
+from xen.xend import sxp
+from xen.xend import XendDomain
+from xen.xend.Args import FormFn
+
+from SrvDir import SrvDir
+from SrvDomain import SrvDomain
+
+class SrvDomainDir(SrvDir):
+ """Service that manages the domain directory.
+ """
+
+ def __init__(self):
+ SrvDir.__init__(self)
+ self.xd = XendDomain.instance()
+
+ def domain(self, x):
+ val = None
+ try:
+ dom = self.xd.domain_get(x)
+ val = SrvDomain(dom)
+ except KeyError, ex:
+ print 'SrvDomainDir>', ex
+ pass
+ return val
+
+ def get(self, x):
+ v = SrvDir.get(self, x)
+ if v is not None:
+ return v
+ v = self.domain(x)
+ return v
+
+ def op_create(self, op, req):
+ ok = 0
+ try:
+ configstring = req.args.get('config')[0]
+ print 'config:', configstring
+ pin = sxp.Parser()
+ pin.input(configstring)
+ pin.input_eof()
+ config = pin.get_val()
+ ok = 1
+ except Exception, ex:
+ print 'op_create>', ex
+ if not ok:
+ req.setResponseCode(http.BAD_REQUEST, "Invalid configuration")
+ return "Invalid configuration"
+ return error.ErrorPage(http.BAD_REQUEST,
+ "Invalid",
+ "Invalid configuration")
+ try:
+ deferred = self.xd.domain_create(config)
+ deferred.addCallback(self._cb_op_create, configstring, req)
+ return deferred
+ except Exception, ex:
+ raise
+ #return ['err', str(ex) ]
+ #req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
+ #return str(ex)
+ #return error.ErrorPage(http.BAD_REQUEST,
+ # "Error creating domain",
+ # str(ex))
+
+
+ def _cb_op_create(self, dominfo, configstring, req):
+ """Callback to handle deferred domain creation.
+ """
+ dom = dominfo.id
+ domurl = "%s/%s" % (req.prePathURL(), dom)
+ req.setResponseCode(201, "created")
+ req.setHeader("Location", domurl)
+ if self.use_sxp(req):
+ return dominfo.sxpr()
+ else:
+ out = StringIO()
+ print >> out, ('<p> Created <a href="%s">Domain %s</a></p>'
+ % (domurl, dom))
+ print >> out, '<p><pre>'
+ print >> out, configstring
+ print >> out, '</pre></p>'
+ val = out.getvalue()
+ out.close()
+ return val
+
+ def op_restore(self, op, req):
+ fn = FormFn(self.xd.domain_restore,
+ [['file', 'str']])
+ val = fn(req.args)
+ return val
+
+ def render_POST(self, req):
+ return self.perform(req)
+
+ def render_GET(self, req):
+ if self.use_sxp(req):
+ req.setHeader("Content-Type", sxp.mime_type)
+ self.ls_domain(req, 1)
+ else:
+ req.write("<html><head></head><body>")
+ self.print_path(req)
+ self.ls(req)
+ self.ls_domain(req)
+ self.form(req)
+ req.write("</body></html>")
+ return ''
+
+ def ls_domain(self, req, use_sxp=0):
+ url = req.prePathURL()
+ if not url.endswith('/'):
+ url += '/'
+ if use_sxp:
+ domains = self.xd.domain_ls()
+ sxp.show(domains, out=req)
+ else:
+ domains = self.xd.domains()
+ domains.sort(lambda x, y: cmp(x.id, y.id))
+ req.write('<ul>')
+ for d in domains:
+ req.write('<li><a href="%s%s"> Domain %s</a>'
+ % (url, d.id, d.id))
+ req.write('name=%s' % d.name)
+ req.write('memory=%d'% d.memory)
+ req.write('</li>')
+ req.write('</ul>')
+
+ def form(self, req):
+ req.write('<form method="post" action="%s" enctype="multipart/form-data">'
+ % req.prePathURL())
+ req.write('<button type="submit" name="op" value="create">Create Domain</button>')
+ req.write('Config <input type="file" name="config"><br>')
+ req.write('</form>')
+ req.write('<form method="post" action="%s" enctype="multipart/form-data">'
+ % req.prePathURL())
+ req.write('<button type="submit" name="op" value="create">Restore Domain</button>')
+ req.write('State <input type="string" name="state"><br>')
+ req.write('</form>')
+
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+from xen.xend import sxp
+from xen.xend import EventServer
+from SrvDir import SrvDir
+
+class SrvEventDir(SrvDir):
+ """Event directory.
+ """
+
+ def __init__(self):
+ SrvDir.__init__(self)
+ self.eserver = EventServer.instance()
+
+ def op_inject(self, op, req):
+ eventstring = req.args.get('event')
+ pin = sxp.Parser()
+ pin.input(eventstring)
+ pin.input_eof()
+ sxpr = pin.get_val()
+ self.eserver.inject(sxp.name(sxpr), sxpr)
+ if req.use_sxp:
+ sxp.name(sxpr)
+ else:
+ return '<code>' + eventstring + '</code>'
+
+ def render_POST(self, req):
+ return self.perform(req)
+
+ def form(self, req):
+ action = req.prePathURL()
+ req.write('<form method="post" action="%s" enctype="multipart/form-data">'
+ % action)
+ req.write('<button type="submit" name="op" value="inject">Inject</button>')
+ req.write('Event <input type="text" name="event" size="40"><br>')
+ req.write('</form>')
+ req.write('<form method="post" action="%s" enctype="multipart/form-data">'
+ % action)
+ req.write('<button type="submit" name="op" value="inject">Inject</button>')
+ req.write('Event file<input type="file" name="event"><br>')
+ req.write('</form>')
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+import os
+from SrvDir import SrvDir
+from xen.xend import sxp
+from xen.xend import XendNode
+
+class SrvNode(SrvDir):
+ """Information about the node.
+ """
+
+ def __init__(self):
+ SrvDir.__init__(self)
+ self.xn = XendNode.instance()
+
+ def op_shutdown(self, op, req):
+ val = self.xn.shutdown()
+ return val
+
+ def op_reboot(self, op, req):
+ val = self.xn.reboot()
+ return val
+
+ def op_cpu_rrobin_slice_set(self, op, req):
+ fn = FormFn(self.xn.cpu_rrobin_slice_set,
+ [['slice', 'int']])
+ val = fn(req.args, {})
+ return val
+
+ def op_cpu_bvt_slice_set(self, op, req):
+ fn = FormFn(self.xn.cpu_bvt_slice_set,
+ [['slice', 'int']])
+ val = fn(req.args, {})
+ return val
+
+ def render_POST(self, req):
+ return self.perform(req)
+
+ def render_GET(self, req):
+ if self.use_sxp(req):
+ req.setHeader("Content-Type", sxp.mime_type)
+ sxp.show(['node'] + self.info(), out=req)
+ else:
+ req.write('<html><head></head><body>')
+ self.print_path(req)
+ req.write('<ul>')
+ for d in self.info():
+ req.write('<li> %10s: %s' % (d[0], str(d[1])))
+ req.write('</ul>')
+ req.write('</body></html>')
+ return ''
+
+ def info(self):
+ return self.xn.info()
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+from xen.xend import XendRoot
+xroot = XendRoot.instance()
+from SrvDir import SrvDir
+
+class SrvRoot(SrvDir):
+ """The root of the xend server.
+ """
+
+ """Server sub-components. Each entry is (name, class), where
+ 'name' is the entry name and 'class' is the name of its class.
+ """
+ #todo Get this list from the XendRoot config.
+ subdirs = [
+ ('node', 'SrvNode' ),
+ ('domain', 'SrvDomainDir' ),
+ ('console', 'SrvConsoleDir' ),
+ ('event', 'SrvEventDir' ),
+ ('device', 'SrvDeviceDir' ),
+ ('vnet', 'SrvVnetDir' ),
+ ]
+
+ def __init__(self):
+ SrvDir.__init__(self)
+ for (name, klass) in self.subdirs:
+ self.add(name, klass)
+ for (name, klass) in self.subdirs:
+ self.get(name)
+ xroot.start()
--- /dev/null
+#!/usr/bin/python2
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+"""Example xend HTTP and console server.
+
+ Can be accessed from a browser or from a program.
+ Do 'python SrvServer.py' to run the server.
+ Then point a web browser at http://localhost:8000/xend and follow the links.
+ Most are stubs, except /domain which has a list of domains and a 'create domain'
+ button.
+
+ You can also access the server from a program.
+ Do 'python XendClient.py' to run a few test operations.
+
+ The data served differs depending on the client (as defined by User-Agent
+ and Accept in the HTTP headers). If the client is a browser, data
+ is returned in HTML, with interactive forms. If the client is a program,
+ data is returned in SXP format, with no forms.
+
+ The server serves to the world by default. To restrict it to the local host
+ change 'interface' in main().
+
+ Mike Wray <mike.wray@hp.com>
+"""
+# todo Support security settings etc. in the config file.
+# todo Support command-line args.
+
+from twisted.web import server
+from twisted.web import resource
+from twisted.internet import reactor
+
+from xen.xend import XendRoot
+xroot = XendRoot.instance()
+
+from xen.xend import Vifctl
+
+from SrvRoot import SrvRoot
+
+def create(port=None, interface=None, bridge=0):
+ if port is None: port = 8000
+ if interface is None: interface = ''
+ if bridge or xroot.rebooted:
+ init_bridge()
+ root = resource.Resource()
+ xend = SrvRoot()
+ root.putChild('xend', xend)
+ site = server.Site(root)
+ reactor.listenTCP(port, site, interface=interface)
+
+def init_bridge():
+ Vifctl.init()
+
+def main(port=None, interface=None):
+ create(port, interface)
+ reactor.run()
+
+
+if __name__ == '__main__':
+ main()
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+from SrvDir import SrvDir
+
+class SrvVnetDir(SrvDir):
+ """Vnet directory.
+ """
+
+ pass
--- /dev/null
+from twisted.internet import defer
+
+from xen.xend import sxp
+from xen.xend import PrettyPrint
+
+import channel
+import controller
+from messages import *
+
+class BlkifControllerFactory(controller.ControllerFactory):
+ """Factory for creating block device interface controllers.
+ Also handles the 'back-end' channel to the device driver domain.
+ """
+
+ def __init__(self):
+ controller.ControllerFactory.__init__(self)
+
+ self.majorTypes = [ CMSG_BLKIF_BE ]
+
+ self.subTypes = {
+ CMSG_BLKIF_BE_CREATE : self.recv_be_create,
+ CMSG_BLKIF_BE_CONNECT : self.recv_be_connect,
+ CMSG_BLKIF_BE_VBD_CREATE : self.recv_be_vbd_create,
+ CMSG_BLKIF_BE_VBD_GROW : self.recv_be_vbd_grow,
+ CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
+ }
+ self.attached = 1
+ self.registerChannel()
+
+ def createInstance(self, dom, recreate=0):
+ d = self.addDeferred()
+ blkif = self.getInstanceByDom(dom)
+ if blkif:
+ self.callDeferred(blkif)
+ else:
+ blkif = BlkifController(self, dom)
+ self.addInstance(blkif)
+ if recreate:
+ self.callDeferred(blkif)
+ else:
+ blkif.send_be_create()
+ return d
+
+ def getDomainDevices(self, dom):
+ blkif = self.getInstanceByDom(dom)
+ return (blkif and blkif.getDevices()) or []
+
+ def getDomainDevice(self, dom, vdev):
+ blkif = self.getInstanceByDom(dom)
+ return (blkif and blkif.getDevice(vdev)) or None
+
+ def setControlDomain(self, dom, recreate=0):
+ if self.dom == dom: return
+ self.deregisterChannel()
+ if not recreate:
+ self.attached = 0
+ self.dom = dom
+ self.registerChannel()
+ #
+ #if xend.blkif.be_port:
+ # xend.blkif.recovery = True
+ #xend.blkif.be_port = xend.main.port_from_dom(dom)
+
+ def getControlDomain(self):
+ return self.dom
+
+ def reattachDevice(self, dom, vdev):
+ blkif = self.getInstanceByDom(dom)
+ if blkif:
+ blkif.reattachDevice(vdev)
+ self.attached = self.devicesAttached()
+ if self.attached:
+ self.reattached()
+
+ def devicesAttached(self):
+ """Check if all devices are attached.
+ """
+ attached = 1
+ for blkif in self.getInstances():
+ if not blkif.attached:
+ attached = 0
+ break
+ return attached
+
+ def reattached(self):
+ for blkif in self.getInstances():
+ blkif.reattached()
+
+ def recv_be_create(self, msg, req):
+ #print 'recv_be_create>'
+ val = unpackMsg('blkif_be_create_t', msg)
+ blkif = self.getInstanceByDom(val['domid'])
+ self.callDeferred(blkif)
+
+ def recv_be_connect(self, msg, req):
+ #print 'recv_be_create>'
+ val = unpackMsg('blkif_be_connect_t', msg)
+ blkif = self.getInstanceByDom(val['domid'])
+ if blkif:
+ blkif.send_fe_interface_status_changed()
+ else:
+ pass
+
+ def recv_be_vbd_create(self, msg, req):
+ #print 'recv_be_vbd_create>'
+ val = unpackMsg('blkif_be_vbd_create_t', msg)
+ blkif = self.getInstanceByDom(val['domid'])
+ if blkif:
+ blkif.send_be_vbd_grow(val['vdevice'])
+ else:
+ pass
+
+ def recv_be_vbd_grow(self, msg, req):
+ #print 'recv_be_vbd_grow>'
+ val = unpackMsg('blkif_be_vbd_grow_t', msg)
+ # Check status?
+ if self.attached:
+ self.callDeferred(0)
+ else:
+ self.reattachDevice(val['domid'], val['vdevice'])
+
+ def recv_be_driver_status_changed(self, msg, req):
+ val = unpackMsg('blkif_be_driver_status_changed_t', msg)
+ status = val['status']
+ if status == BLKIF_DRIVER_STATUS_UP and not self.attached:
+ for blkif in self.getInstances():
+ blkif.detach()
+
+class BlkDev(controller.Dev):
+ """Info record for a block device.
+ """
+
+ def __init__(self, ctrl, vdev, mode, segment):
+ controller.Dev.__init__(self, ctrl)
+ self.vdev = vdev
+ self.mode = mode
+ self.device = segment['device']
+ self.start_sector = segment['start_sector']
+ self.nr_sectors = segment['nr_sectors']
+ self.attached = 1
+
+ def readonly(self):
+ return 'w' not in self.mode
+
+ def sxpr(self):
+ val = ['blkdev', ['vdev', self.vdev], ['mode', self.mode] ]
+ return val
+
+ def destroy(self):
+ print 'BlkDev>destroy>', self.vdev
+ PrettyPrint.prettyprint(self.sxpr())
+ self.controller.send_be_vbd_destroy(self.vdev)
+
+class BlkifController(controller.Controller):
+ """Block device interface controller. Handles all block devices
+ for a domain.
+ """
+
+ def __init__(self, factory, dom):
+ #print 'BlkifController> dom=', dom
+ controller.Controller.__init__(self, factory, dom)
+ self.devices = {}
+
+ self.majorTypes = [ CMSG_BLKIF_FE ]
+
+ self.subTypes = {
+ CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED:
+ self.recv_fe_driver_status_changed,
+ CMSG_BLKIF_FE_INTERFACE_CONNECT :
+ self.recv_fe_interface_connect,
+ }
+ self.attached = 1
+ self.evtchn = None
+ self.registerChannel()
+ #print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx
+
+ def sxpr(self):
+ val = ['blkif', ['dom', self.dom]]
+ if self.evtchn:
+ val.append(['evtchn',
+ self.evtchn['port1'],
+ self.evtchn['port2']])
+ return val
+
+ def lostChannel(self):
+ print 'BlkifController>lostChannel>', 'dom=', self.dom
+ #self.destroyDevices()
+ controller.Controller.lostChannel(self)
+
+ def getDevices(self):
+ return self.devices.values()
+
+ def getDevice(self, vdev):
+ return self.devices.get(vdev)
+
+ def addDevice(self, vdev, mode, segment):
+ if vdev in self.devices: return None
+ dev = BlkDev(self, vdev, mode, segment)
+ self.devices[vdev] = dev
+ return dev
+
+ def attachDevice(self, vdev, mode, segment, recreate=0):
+ """Attach a device to the specified interface.
+ """
+ #print 'BlkifController>attach_device>', self.dom, vdev, mode, segment
+ dev = self.addDevice(vdev, mode, segment)
+ if not dev: return -1
+ if recreate:
+ d = defer.Deferred()
+ d.callback(self)
+ else:
+ self.send_be_vbd_create(vdev)
+ d = self.factory.addDeferred()
+ return d
+
+ def destroy(self):
+ print 'BlkifController>destroy> dom=', self.dom
+ def cb_destroy(val):
+ self.send_be_destroy()
+ d = self.factory.addDeferred()
+ d.addCallback(cb_destroy)
+ self.send_be_disconnect()
+ #self.destroyDevices()
+
+ def destroyDevices(self):
+ for dev in self.getDevices():
+ dev.destroy()
+
+ def detach(self):
+ """Detach all devices, when the back-end control domain has changed.
+ """
+ self.attached = 0
+ for dev in self.devices.values():
+ dev.attached = 0
+ self.send_be_vbd_create(vdev)
+
+ def reattachDevice(self, vdev):
+ """Reattach a device, when the back-end control domain has changed.
+ """
+ dev = self.devices[vdev]
+ dev.attached = 1
+ attached = 1
+ for dev in self.devices.values():
+ if not dev.attached:
+ attached = 0
+ break
+ self.attached = attached
+ return self.attached
+
+ def reattached(self):
+ """All devices have been reattached after the back-end control
+ domain has changed.
+ """
+ msg = packMsg('blkif_fe_interface_status_changed_t',
+ { 'handle' : 0,
+ 'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED})
+ self.writeRequest(msg)
+
+ def recv_fe_driver_status_changed(self, msg, req):
+ msg = packMsg('blkif_fe_interface_status_changed_t',
+ { 'handle' : 0,
+ 'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED,
+ 'evtchn' : 0 })
+ self.writeRequest(msg)
+
+ def recv_fe_interface_connect(self, msg, req):
+ val = unpackMsg('blkif_fe_interface_connect_t', msg)
+ self.evtchn = channel.eventChannel(0, self.dom)
+ print 'recv_fe_interface_connect>'
+ PrettyPrint.prettyprint(self.sxpr())
+ msg = packMsg('blkif_be_connect_t',
+ { 'domid' : self.dom,
+ 'blkif_handle' : val['handle'],
+ 'evtchn' : self.evtchn['port1'],
+ 'shmem_frame' : val['shmem_frame'] })
+ self.factory.writeRequest(msg)
+ pass
+
+ #def recv_fe_interface_status_changed(self, msg, req):
+ # (hnd, status, chan) = unpackMsg('blkif_fe_interface_status_changed_t', msg)
+ # print 'recv_fe_interface_status_changed>', hnd, status, chan
+ # pass
+
+ def send_fe_interface_status_changed(self):
+ msg = packMsg('blkif_fe_interface_status_changed_t',
+ { 'handle' : 0,
+ 'status' : BLKIF_INTERFACE_STATUS_CONNECTED,
+ 'evtchn' : self.evtchn['port2'] })
+ self.writeRequest(msg)
+
+ def send_be_create(self):
+ msg = packMsg('blkif_be_create_t',
+ { 'domid' : self.dom,
+ 'blkif_handle' : 0 })
+ self.factory.writeRequest(msg)
+
+ def send_be_disconnect(self):
+ print '>BlkifController>send_be_disconnect>', 'dom=', self.dom
+ msg = packMsg('blkif_be_disconnect_t',
+ { 'domid' : self.dom,
+ 'blkif_handle' : 0 })
+ self.factory.writeRequest(msg)
+
+ def send_be_destroy(self):
+ print '>BlkifController>send_be_destroy>', 'dom=', self.dom
+ msg = packMsg('blkif_be_destroy_t',
+ { 'domid' : self.dom,
+ 'blkif_handle' : 0 })
+ self.factory.writeRequest(msg)
+
+ def send_be_vbd_create(self, vdev):
+ dev = self.devices[vdev]
+ msg = packMsg('blkif_be_vbd_create_t',
+ { 'domid' : self.dom,
+ 'blkif_handle' : 0,
+ 'vdevice' : dev.vdev,
+ 'readonly' : dev.readonly() })
+ self.factory.writeRequest(msg)
+
+ def send_be_vbd_grow(self, vdev):
+ dev = self.devices[vdev]
+ msg = packMsg('blkif_be_vbd_grow_t',
+ { 'domid' : self.dom,
+ 'blkif_handle' : 0,
+ 'vdevice' : dev.vdev,
+ 'extent.device' : dev.device,
+ 'extent.sector_start' : dev.start_sector,
+ 'extent.sector_length' : dev.nr_sectors })
+ self.factory.writeRequest(msg)
+
+ def send_be_vbd_destroy(self, vdev):
+ print '>BlkifController>send_be_vbd_destroy>', 'dom=', self.dom, 'vdev=', vdev
+ PrettyPrint.prettyprint(self.sxpr())
+ dev = self.devices[vdev]
+ msg = packMsg('blkif_be_vbd_destroy_t',
+ { 'domid' : self.dom,
+ 'blkif_handle' : 0,
+ 'vdevice' : dev.vdev })
+ del self.devices[vdev]
+ self.factory.writeRequest(msg)
+
--- /dev/null
+import xen.ext.xc; xc = xen.ext.xc.new()
+from xen.ext import xu
+from messages import msgTypeName
+
+VIRQ_MISDIRECT = 0 # Catch-all interrupt for unbound VIRQs.
+VIRQ_TIMER = 1 # Timebase update, and/or requested timeout.
+VIRQ_DEBUG = 2 # Request guest to dump debug info.
+VIRQ_CONSOLE = 3 # (DOM0) bytes received on emergency console.
+VIRQ_DOM_EXC = 4 # (DOM0) Exceptional event for some domain.
+
+def eventChannel(dom1, dom2):
+ return xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2)
+
+class ChannelFactory:
+ """Factory for creating channels.
+ Maintains a table of channels.
+ """
+
+ """ Channels indexed by index. """
+ channels = {}
+
+ def __init__(self):
+ """Constructor - do not use. Use the channelFactory function."""
+ self.notifier = xu.notifier()
+
+ def addChannel(self, channel):
+ """Add a channel.
+ """
+ idx = channel.idx
+ self.channels[idx] = channel
+ self.notifier.bind(idx)
+ # Try to wake it up
+ #self.notifier.unmask(idx)
+ #channel.notify()
+
+ def getChannel(self, idx):
+ """Get the channel with the given index (if any).
+ """
+ return self.channels.get(idx)
+
+ def delChannel(self, idx):
+ """Remove the channel with the given index (if any).
+ """
+ if idx in self.channels:
+ del self.channels[idx]
+ self.notifier.unbind(idx)
+
+ def domChannel(self, dom):
+ """Get the channel for the given domain.
+ Construct if necessary.
+ """
+ dom = int(dom)
+ for chan in self.channels.values():
+ if not isinstance(chan, Channel): continue
+ if chan.dom == dom:
+ return chan
+ chan = Channel(self, dom)
+ self.addChannel(chan)
+ return chan
+
+ def virqChannel(self, virq):
+ """Get the channel for the given virq.
+ Construct if necessary.
+ """
+ for chan in self.channels.values():
+ if not isinstance(chan, VirqChannel): continue
+ if chan.virq == virq:
+ return chan
+ chan = VirqChannel(self, virq)
+ self.addChannel(chan)
+ return chan
+
+ def channelClosed(self, channel):
+ """The given channel has been closed - remove it.
+ """
+ self.delChannel(channel.idx)
+
+ def createPort(self, dom):
+ """Create a port for a channel to the given domain.
+ """
+ return xu.port(dom)
+
+def channelFactory():
+ """Singleton constructor for the channel factory.
+ Use this instead of the class constructor.
+ """
+ global inst
+ try:
+ inst
+ except:
+ inst = ChannelFactory()
+ return inst
+
+class BaseChannel:
+ """Abstract superclass for channels.
+
+ The subclass constructor must set idx to the port to use.
+ """
+
+ def __init__(self, factory):
+ self.factory = factory
+ self.idx = -1
+ self.closed = 0
+
+ def getIndex(self):
+ """Get the channel index.
+ """
+ return self.idx
+
+ def notificationReceived(self, type):
+ """Called when a notification is received.
+ Closes the channel on error, otherwise calls
+ handleNotification(type), which should be defined
+ in a subclass.
+ """
+ #print 'notificationReceived> type=', type, self
+ if self.closed: return
+ if type == self.factory.notifier.EXCEPTION:
+ print 'notificationReceived> EXCEPTION'
+ info = xc.evtchn_status(self.idx)
+ if info['status'] == 'unbound':
+ print 'notificationReceived> EXCEPTION closing...'
+ self.close()
+ return
+ self.handleNotification(type)
+
+ def close(self):
+ """Close the channel. Calls channelClosed() on the factory.
+ Override in subclass.
+ """
+ self.factory.channelClosed(self)
+
+ def handleNotification(self, type):
+ """Handle notification.
+ Define in subclass.
+ """
+ pass
+
+
+class VirqChannel(BaseChannel):
+ """A channel for handling a virq.
+ """
+
+ def __init__(self, factory, virq):
+ """Create a channel for the given virq using the given factory.
+
+ Do not call directly, use virqChannel on the factory.
+ """
+ BaseChannel.__init__(self, factory)
+ self.virq = virq
+ # Notification port (int).
+ self.port = xc.evtchn_bind_virq(virq)
+ self.idx = self.port
+ # Clients to call when a virq arrives.
+ self.clients = []
+
+ def __repr__(self):
+ return ('<VirqChannel virq=%d port=%d>'
+ % (self.virq, self.port))
+
+ def getVirq(self):
+ """Get the channel's virq.
+ """
+ return self.virq
+
+ def close(self):
+ """Close the channel. Calls lostChannel(self) on all its clients and
+ channelClosed() on the factory.
+ """
+ for c in self.clients:
+ c.lostChannel(self)
+ del self.clients
+ BaseChannel.close(self)
+
+ def registerClient(self, client):
+ """Register a client. The client will be called with
+ client.virqReceived(virq) when a virq is received.
+ The client will be called with client.lostChannel(self) if the
+ channel is closed.
+ """
+ self.clients.append(client)
+
+ def handleNotification(self, type):
+ for c in self.clients:
+ c.virqReceived(self.virq)
+
+ def notify(self):
+ xc.evtchn_send(self.port)
+
+
+class Channel(BaseChannel):
+ """A control channel to a domain. Messages for the domain device controllers
+ are multiplexed over the channel (console, block devs, net devs).
+ """
+
+ def __init__(self, factory, dom):
+ """Create a channel to the given domain using the given factory.
+
+ Do not call directly, use domChannel on the factory.
+ """
+ BaseChannel.__init__(self, factory)
+ # Domain.
+ self.dom = int(dom)
+ # Domain port (object).
+ self.port = self.factory.createPort(dom)
+ # Channel port (int).
+ self.idx = self.port.local_port
+ # Registered devices.
+ self.devs = []
+ # Devices indexed by the message types they handle.
+ self.devs_by_type = {}
+ # Output queue.
+ self.queue = []
+ self.closed = 0
+
+ def getLocalPort(self):
+ """Get the local port.
+ """
+ return self.port.local_port
+
+ def getRemotePort(self):
+ """Get the remote port.
+ """
+ return self.port.remote_port
+
+ def close(self):
+ """Close the channel. Calls lostChannel() on all its devices and
+ channelClosed() on the factory.
+ """
+ self.closed = 1
+ for d in self.devs:
+ d.lostChannel()
+ self.factory.channelClosed(self)
+ self.devs = []
+ self.devs_by_type = {}
+
+ def registerDevice(self, types, dev):
+ """Register a device controller.
+
+ @param types message types the controller handles
+ @param dev device controller
+ """
+ if self.closed: return
+ self.devs.append(dev)
+ for ty in types:
+ self.devs_by_type[ty] = dev
+
+ def deregisterDevice(self, dev):
+ """Remove the registration for a device controller.
+
+ @param dev device controller
+ """
+ if dev in self.devs:
+ self.devs.remove(dev)
+ types = [ ty for (ty, d) in self.devs_by_type.items() if d == dev ]
+ for ty in types:
+ del self.devs_by_type[ty]
+
+ def getDevice(self, type):
+ """Get the device controller handling a message type.
+
+ @param type message type
+ @returns controller or None
+ """
+ return self.devs_by_type.get(type)
+
+ def getMessageType(self, msg):
+ """Get a 2-tuple of the message type and subtype.
+ """
+ hdr = msg.get_header()
+ return (hdr['type'], hdr.get('subtype'))
+
+ def __repr__(self):
+ return ('<Channel dom=%d ports=%d:%d>'
+ % (self.dom,
+ self.port.local_port,
+ self.port.remote_port))
+
+ def handleNotification(self, type):
+ work = 0
+ work += self.handleRequests()
+ work += self.handleResponses()
+ work += self.handleWrites()
+ if work:
+ self.notify()
+
+ def notify(self):
+ self.port.notify()
+
+ def handleRequests(self):
+ work = 0
+ while 1:
+ msg = self.readRequest()
+ if not msg: break
+ self.requestReceived(msg)
+ work += 1
+ return work
+
+ def requestReceived(self, msg):
+ (ty, subty) = self.getMessageType(msg)
+ #todo: Must respond before writing any more messages.
+ #todo: Should automate this (respond on write)
+ self.port.write_response(msg)
+ dev = self.getDevice(ty)
+ if dev:
+ dev.requestReceived(msg, ty, subty)
+ else:
+ print ("requestReceived> No device: Message type %s %d:%d"
+ % (msgTypeName(ty, subty), ty, subty)), self
+
+ def handleResponses(self):
+ work = 0
+ while 1:
+ msg = self.readResponse()
+ if not msg: break
+ self.responseReceived(msg)
+ work += 1
+ return work
+
+ def responseReceived(self, msg):
+ (ty, subty) = self.getMessageType(msg)
+ dev = self.getDevice(ty)
+ if dev:
+ dev.responseReceived(msg, ty, subty)
+ else:
+ print ("responseReceived> No device: Message type %d:%d"
+ % (msgTypeName(ty, subty), ty, subty)), self
+
+ def handleWrites(self):
+ work = 0
+ # Pull data from producers.
+ for dev in self.devs:
+ work += dev.produceRequests()
+ # Flush the queue.
+ while self.queue and self.port.space_to_write_request():
+ msg = self.queue.pop(0)
+ self.port.write_request(msg)
+ work += 1
+ return work
+
+ def writeRequest(self, msg, notify=1):
+ if self.closed:
+ val = -1
+ elif self.writeReady():
+ self.port.write_request(msg)
+ if notify: self.notify()
+ val = 1
+ else:
+ self.queue.append(msg)
+ val = 0
+ return val
+
+ def writeResponse(self, msg):
+ if self.closed: return -1
+ self.port.write_response(msg)
+ return 1
+
+ def writeReady(self):
+ if self.closed or self.queue: return 0
+ return self.port.space_to_write_request()
+
+ def readRequest(self):
+ if self.closed:
+ return None
+ if self.port.request_to_read():
+ val = self.port.read_request()
+ else:
+ val = None
+ return val
+
+ def readResponse(self):
+ if self.closed:
+ return None
+ if self.port.response_to_read():
+ val = self.port.read_response()
+ else:
+ val = None
+ return val
--- /dev/null
+
+from twisted.internet import reactor
+from twisted.internet import protocol
+from twisted.protocols import telnet
+
+from xen.ext import xu
+
+from xen.xend import EventServer
+eserver = EventServer.instance()
+
+import controller
+from messages import *
+from params import *
+
+"""Telnet binary option."""
+TRANSMIT_BINARY = '0'
+WILL = chr(251)
+IAC = chr(255)
+
+class ConsoleProtocol(protocol.Protocol):
+ """Asynchronous handler for a console TCP socket.
+ """
+
+ def __init__(self, controller, idx):
+ self.controller = controller
+ self.idx = idx
+ self.addr = None
+ self.binary = 0
+
+ def connectionMade(self):
+ peer = self.transport.getPeer()
+ self.addr = (peer.host, peer.port)
+ if self.controller.connect(self.addr, self):
+ self.transport.write("Cannot connect to console %d on domain %d\n"
+ % (self.idx, self.controller.dom))
+ self.loseConnection()
+ return
+ else:
+ # KAF: A nice quiet successful connect. Don't bother with telnet
+ # control sequence -- telnet is not the appropriate protocol here.
+ #self.transport.write("Connected to console %d on domain %d\n"
+ # % (self.idx, self.controller.dom))
+ #self.setTelnetTransmitBinary()
+ eserver.inject('xend.console.connect',
+ [self.idx, self.addr[0], self.addr[1]])
+
+ def setTelnetTransmitBinary(self):
+ """Send the sequence to set the telnet TRANSMIT-BINARY option.
+ """
+ self.write(IAC + WILL + TRANSMIT_BINARY)
+
+ def dataReceived(self, data):
+ if self.controller.handleInput(self, data):
+ self.loseConnection()
+
+ def write(self, data):
+ #if not self.connected: return -1
+ self.transport.write(data)
+ return len(data)
+
+ def connectionLost(self, reason=None):
+ eserver.inject('xend.console.disconnect',
+ [self.idx, self.addr[0], self.addr[1]])
+ self.controller.disconnect()
+
+ def loseConnection(self):
+ self.transport.loseConnection()
+
+class ConsoleFactory(protocol.ServerFactory):
+ """Asynchronous handler for a console server socket.
+ """
+ protocol = ConsoleProtocol
+
+ def __init__(self, controller, idx):
+ #protocol.ServerFactory.__init__(self)
+ self.controller = controller
+ self.idx = idx
+
+ def buildProtocol(self, addr):
+ proto = self.protocol(self.controller, self.idx)
+ proto.factory = self
+ return proto
+
+class ConsoleControllerFactory(controller.ControllerFactory):
+ """Factory for creating console controllers.
+ """
+
+ def createInstance(self, dom, console_port=None):
+ if console_port is None:
+ console_port = CONSOLE_PORT_BASE + dom
+ console = ConsoleController(self, dom, console_port)
+ self.addInstance(console)
+ eserver.inject('xend.console.create',
+ [console.idx, console.dom, console.console_port])
+ return console
+
+ def consoleClosed(self, console):
+ eserver.inject('xend.console.close', console.idx)
+ self.delInstance(console)
+
+class ConsoleController(controller.Controller):
+ """Console controller for a domain.
+ Does not poll for i/o itself, but relies on the notifier to post console
+ output and the connected TCP sockets to post console input.
+ """
+
+ def __init__(self, factory, dom, console_port):
+ #print 'ConsoleController> dom=', dom, type(dom)
+ controller.Controller.__init__(self, factory, dom)
+ self.majorTypes = [ CMSG_CONSOLE ]
+ self.status = "new"
+ self.addr = None
+ self.conn = None
+ self.rbuf = xu.buffer()
+ self.wbuf = xu.buffer()
+ self.console_port = console_port
+
+ self.registerChannel()
+ self.listener = None
+ self.listen()
+ #print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx
+
+ def sxpr(self):
+ val =['console',
+ ['status', self.status ],
+ ['id', self.idx ],
+ ['domain', self.dom ],
+ ['local_port', self.channel.getLocalPort() ],
+ ['remote_port', self.channel.getRemotePort() ],
+ ['console_port', self.console_port ] ]
+ if self.addr:
+ val.append(['connected', self.addr[0], self.addr[1]])
+ return val
+
+ def ready(self):
+ return not (self.closed() or self.rbuf.empty())
+
+ def closed(self):
+ return self.status == 'closed'
+
+ def connected(self):
+ return self.status == 'connected'
+
+ def close(self):
+ try:
+ #print 'ConsoleController> close dom=', self.dom
+ self.status = "closed"
+ if self.conn:
+ self.conn.loseConnection()
+ self.listener.stopListening()
+ self.deregisterChannel()
+ self.lostChannel()
+ except Exception, ex:
+ print 'ConsoleController>close>', ex
+ raise
+
+ def listen(self):
+ """Listen for TCP connections to the console port..
+ """
+ if self.closed(): return
+ self.status = "listening"
+ if self.listener:
+ #self.listener.startListening()
+ pass
+ else:
+ f = ConsoleFactory(self, self.idx)
+ self.listener = reactor.listenTCP(self.console_port, f)
+
+ def connect(self, addr, conn):
+ if self.closed(): return -1
+ if self.connected(): return -1
+ self.addr = addr
+ self.conn = conn
+ self.status = "connected"
+ self.handleOutput()
+ return 0
+
+ def disconnect(self):
+ if self.conn:
+ self.conn.loseConnection()
+ self.addr = None
+ self.conn = None
+ self.listen()
+
+ def requestReceived(self, msg, type, subtype):
+ #print '***Console', self.dom, msg.get_payload()
+ self.rbuf.write(msg.get_payload())
+ self.handleOutput()
+
+ def responseReceived(self, msg, type, subtype):
+ pass
+
+ def produceRequests(self):
+ # Send as much pending console data as there is room for.
+ work = 0
+ while not self.wbuf.empty() and self.channel.writeReady():
+ msg = xu.message(CMSG_CONSOLE, 0, 0)
+ msg.append_payload(self.wbuf.read(msg.MAX_PAYLOAD))
+ work += self.channel.writeRequest(msg, notify=0)
+ return work
+
+ def handleInput(self, conn, data):
+ """Handle some external input aimed at the console.
+ Called from a TCP connection (conn).
+ """
+ if self.closed(): return -1
+ if conn != self.conn: return 0
+ self.wbuf.write(data)
+ if self.produceRequests():
+ self.channel.notify()
+ return 0
+
+ def handleOutput(self):
+ """Handle buffered output from the console.
+ Sends it to the connected console (if any).
+ """
+ if self.closed():
+ #print 'Console>handleOutput> closed'
+ return -1
+ if not self.conn:
+ #print 'Console>handleOutput> not connected'
+ return 0
+ while not self.rbuf.empty():
+ try:
+ #print 'Console>handleOutput> writing...'
+ bytes = self.conn.write(self.rbuf.peek())
+ if bytes > 0:
+ self.rbuf.discard(bytes)
+ except socket.error, error:
+ pass
+ #print 'Console>handleOutput<'
+ return 0
--- /dev/null
+from twisted.internet import defer
+
+import channel
+from messages import msgTypeName
+
+class CtrlMsgRcvr:
+ """Abstract class for things that deal with a control interface to a domain.
+ """
+
+
+ def __init__(self):
+ self.channelFactory = channel.channelFactory()
+ self.majorTypes = [ ]
+ self.subTypes = {}
+ self.dom = None
+ self.channel = None
+ self.idx = None
+
+ def requestReceived(self, msg, type, subtype):
+ method = self.subTypes.get(subtype)
+ if method:
+ method(msg, 1)
+ else:
+ print ('requestReceived> No handler: Message type %s %d:%d'
+ % (msgTypeName(type, subtype), type, subtype)), self
+
+ def responseReceived(self, msg, type, subtype):
+ method = self.subTypes.get(subtype)
+ if method:
+ method(msg, 0)
+ else:
+ print ('responseReceived> No handler: Message type %s %d:%d'
+ % (msgTypeName(type, subtype), type, subtype)), self
+
+ def lostChannel(self):
+ pass
+
+ def registerChannel(self):
+ #print 'CtrlMsgRcvr>registerChannel>', self
+ self.channel = self.channelFactory.domChannel(self.dom)
+ self.idx = self.channel.getIndex()
+ if self.majorTypes:
+ self.channel.registerDevice(self.majorTypes, self)
+
+ def deregisterChannel(self):
+ #print 'CtrlMsgRcvr>deregisterChannel>', self
+ if self.channel:
+ self.channel.deregisterDevice(self)
+ del self.channel
+
+ def produceRequests(self):
+ return 0
+
+ def writeRequest(self, msg):
+ if self.channel:
+ self.channel.writeRequest(msg)
+ else:
+ print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self
+
+ def writeResponse(self, msg):
+ if self.channel:
+ self.channel.writeResponse(msg)
+ else:
+ print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self
+
+class ControllerFactory(CtrlMsgRcvr):
+ """Abstract class for factories creating controllers.
+ Maintains a table of instances.
+ """
+
+ def __init__(self):
+ CtrlMsgRcvr.__init__(self)
+ self.instances = {}
+ self.dlist = []
+ self.dom = 0
+ # Timeout (in seconds) for deferreds.
+ self.timeout = 10
+
+ def addInstance(self, instance):
+ self.instances[instance.idx] = instance
+
+ def getInstance(self, idx):
+ return self.instances.get(idx)
+
+ def getInstances(self):
+ return self.instances.values()
+
+ def getInstanceByDom(self, dom):
+ for inst in self.instances.values():
+ if inst.dom == dom:
+ return inst
+ return None
+
+ def delInstance(self, instance):
+ #print 'ControllerFactory>delInstance>', instance.idx
+ if instance.idx in self.instances:
+ #print 'ControllerFactory>delInstance> remove', instance.idx
+ del self.instances[instance.idx]
+
+ def createInstance(self, dom, recreate=0):
+ raise NotImplementedError()
+
+ def instanceClosed(self, instance):
+ #print 'ControllerFactory>instanceClosed>', instance.idx, instance
+ self.delInstance(instance)
+
+ def addDeferred(self):
+ d = defer.Deferred()
+ if self.timeout > 0:
+ # The deferred will error if not called before timeout.
+ d.setTimeout(self.timeout)
+ self.dlist.append(d)
+ return d
+
+ def callDeferred(self, *args):
+ if self.dlist:
+ d = self.dlist.pop(0)
+ d.callback(*args)
+
+ def errDeferred(self, *args):
+ if self.dlist:
+ d = self.dlist.pop(0)
+ d.errback(*args)
+
+class Controller(CtrlMsgRcvr):
+ """Abstract class for a device controller attached to a domain.
+ """
+
+ def __init__(self, factory, dom):
+ CtrlMsgRcvr.__init__(self)
+ self.factory = factory
+ self.dom = int(dom)
+ self.channel = None
+ self.idx = None
+
+ def close(self):
+ self.deregisterChannel()
+ self.lostChannel()
+
+ def lostChannel(self):
+ #print 'Controller>lostChannel>', self, self.factory
+ self.factory.instanceClosed(self)
+
+class Dev:
+
+ def __init__(self, controller):
+ self.controller = controller
+ self.props = {}
+
+ def setprop(self, k, v):
+ self.props[k] = v
+
+ def getprop(self, k, v=None):
+ return self.props.get(k, v)
+
+ def hasprop(self, k):
+ return k in self.props
+
+ def delprop(self, k):
+ if k in self.props:
+ del self.props[k]
+
+ #def __repr__(self):
+ # return str(self.sxpr())
+
+ def sxpr(self):
+ raise NotImplementedError()
+
+
--- /dev/null
+import struct
+
+class Struct:
+
+ maxDepth = 10
+
+ base = ['x', 'B', 'H', 'I', 'L', 'Q', 'c', 'h', 'i', 'l', 'q', ]
+
+ sizes = {'B': 1,
+ 'H': 2,
+ 'I': 4,
+ 'L': 4,
+ 'Q': 8,
+ 'c': 1,
+ 'h': 2,
+ 'i': 4,
+ 'l': 4,
+ 'q': 8,
+ 'x': 1,
+ }
+
+ formats = {
+ 'int8' : 'B',
+ 'int16' : 'H',
+ 'int32' : 'I',
+ 'int64' : 'Q',
+ 'u8' : 'B',
+ 'u16' : 'H',
+ 'u32' : 'I',
+ 'u64' : 'Q'
+ }
+
+ def typedef(self, name, val):
+ self.formats[name] = val
+
+ def struct(self, name, *f):
+ self.typedef(name, StructInfo(self, f))
+
+ def getType(self, name):
+ return self.formats[name]
+
+ def format(self, ty):
+ d = 0
+ f = ty
+ while d < self.maxDepth:
+ d += 1
+ f = self.formats[f]
+ if isinstance(f, StructInfo):
+ return f.format()
+ if f in self.base:
+ return f
+ return -1
+
+ def alignedformat(self, ty):
+ fmt = self.format(ty)
+ #print 'alignedformat> %s |%s|' %(ty, fmt)
+ afmt = self.align(fmt)
+ #print 'alignedformat< %s |%s| |%s|' % (ty, fmt, afmt)
+ return afmt
+
+ def align(self, fmt):
+ n1 = 0
+ afmt = ''
+ for a in fmt:
+ n2 = self.getSize(a)
+ m = n1 % n2
+ if m:
+ d = (n2 - m)
+ afmt += 'x' * d
+ n1 += d
+ afmt += a
+ n1 += n2
+ return afmt
+
+ def fmtsize(self, fmt):
+ s = 0
+ for f in fmt:
+ s += self.getSize(f)
+ return s
+
+ def getSize(self, f):
+ return self.sizes[f]
+
+ def pack(self, ty, data):
+ return self.getType(ty).pack(data)
+
+ def unpack(self, ty, data):
+ return self.getType(ty).unpack(data)
+
+ def show(self):
+ l = self.formats.keys()
+ l.sort()
+ for v in l:
+ print "%-35s %-10s %s" % (v, self.format(v), self.alignedformat(v))
+
+
+class StructInfo:
+
+ def __init__(self, s, f):
+ self.fmt = None
+ self.structs = s
+ self.fields = f
+
+ def alignedformat(self):
+ if self.afmt: return self.afmt
+ self.afmt = self.structs.align(self.format())
+ return self.afmt
+
+ def format(self):
+ if self.fmt: return self.fmt
+ fmt = ""
+ for (ty, name) in self.fields:
+ fmt += self.formatString(ty)
+ self.fmt = fmt
+ return fmt
+
+ def formatString(self, ty):
+ if ty in self.fields:
+ ty = self.fields[ty]
+ return self.structs.format(ty)
+
+ def pack(self, *args):
+ return struct.pack(self.alignedformat(), *args)
+
+ def unpack(self, data):
+ return struct.unpack(self.alignedformat(), data)
+
+types = Struct()
+
+types.typedef('short' , 'h')
+types.typedef('int' , 'i')
+types.typedef('long' , 'l')
+types.typedef('unsigned short', 'H')
+types.typedef('unsigned int' , 'I')
+types.typedef('unsigned long' , 'L')
+types.typedef('domid_t' , 'u64')
+types.typedef('blkif_vdev_t' , 'u16')
+types.typedef('blkif_pdev_t' , 'u16')
+types.typedef('blkif_sector_t', 'u64')
+
+types.struct('u8[6]',
+ ('u8', 'a1'),
+ ('u8', 'a2'),
+ ('u8', 'a3'),
+ ('u8', 'a4'),
+ ('u8', 'a5'),
+ ('u8', 'a6'))
+
+types.struct('blkif_fe_interface_status_changed_t',
+ ('unsigned int', 'handle'),
+ ('unsigned int', 'status'),
+ ('unsigned int', 'evtchn'))
+
+types.struct('blkif_fe_driver_status_changed_t',
+ ('unsigned int', 'status'),
+ ('unsigned int', 'nr_interfaces'))
+
+types.struct('blkif_fe_interface_connect_t',
+ ('unsigned int' , 'handle'),
+ ('unsigned long', 'shmem_frame'))
+
+types.struct('blkif_fe_interface_disconnect_t',
+ ('unsigned int', 'handle'))
+
+types.struct('blkif_extent_t',
+ ('blkif_pdev_t' , 'device'),
+ ('blkif_sector_t', 'sector_start'),
+ ('blkif_sector_t', 'sector_length'))
+
+types.struct('blkif_be_create_t',
+ ('domid_t' , 'domid'),
+ ('unsigned int', 'blkif_handle'),
+ ('unsigned int', 'status'))
+
+types.struct('blkif_be_destroy_t',
+ ('domid_t' , 'domid'),
+ ('unsigned int', 'blkif_handle'),
+ ('unsigned int', 'status'))
+
+types.struct('blkif_be_connect_t',
+ ('domid_t' , 'domid'),
+ ('unsigned int' , 'blkif_handle'),
+ ('unsigned int' , 'evtchn'),
+ ('unsigned long', 'shmem_frame'),
+ ('unsigned int' , 'status'))
+
+types.struct('blkif_be_disconnect_t',
+ ('domid_t' , 'domid'),
+ ('unsigned int', 'blkif_handle'),
+ ('unsigned int', 'status'))
+
+types.struct('blkif_be_vbd_create_t',
+ ('domid_t' , 'domid'), #Q
+ ('unsigned int', 'blkif_handle'), #I
+ ('blkif_vdev_t', 'vdevice'), #H
+ ('int' , 'readonly'), #i
+ ('unsigned int', 'status')) #I
+
+types.struct('blkif_be_vbd_destroy_t',
+ ('domid_t' , 'domid'),
+ ('unsigned int', 'blkif_handle'),
+ ('blkif_vdev_t', 'vdevice'),
+ ('unsigned int', 'status'))
+
+types.struct('blkif_be_vbd_grow_t',
+ ('domid_t' , 'domid'), #Q
+ ('unsigned int' , 'blkif_handle'), #I
+ ('blkif_vdev_t' , 'vdevice'), #H
+ ('blkif_extent_t', 'extent'), #HQQ
+ ('unsigned int' , 'status')) #I
+
+types.struct('blkif_be_vbd_shrink_t',
+ ('domid_t' , 'domid'),
+ ('unsigned int', 'blkif_handle'),
+ ('blkif_vdev_t', 'vdevice'),
+ ('unsigned int', 'status'))
+
+types.struct('blkif_be_driver_status_changed_t',
+ ('unsigned int', 'status'),
+ ('unsigned int', 'nr_interfaces'))
+
+types.struct('netif_fe_interface_status_changed_t',
+ ('unsigned int', 'handle'),
+ ('unsigned int', 'status'),
+ ('unsigned int', 'evtchn'),
+ ('u8[6]', 'mac'))
+
+types.struct('netif_fe_driver_status_changed_t',
+ ('unsigned int', 'status'),
+ ('unsigned int', 'nr_interfaces'))
+
+types.struct('netif_fe_interface_connect_t',
+ ('unsigned int', 'handle'),
+ ('unsigned long', 'tx_shmem_frame'),
+ ('unsigned long', 'rx_shmem_frame'))
+
+types.struct('netif_fe_interface_disconnect_t',
+ ('unsigned int', 'handle'))
+
+types.struct('netif_be_create_t',
+ ('domid_t' , 'domid'),
+ ('unsigned int', 'netif_handle'),
+ ('u8[6]' , 'mac'),
+ ('unsigned int', 'status'))
+
+types.struct('netif_be_destroy_t',
+ ('domid_t' , 'domid'),
+ ('unsigned int', 'netif_handle'),
+ ('unsigned int', 'status'))
+
+types.struct('netif_be_connect_t',
+ ('domid_t' , 'domid'),
+ ('unsigned int' , 'netif_handle'),
+ ('unsigned int' , 'evtchn'),
+ ('unsigned long', 'tx_shmem_frame'),
+ ('unsigned long', 'rx_shmem_frame'),
+ ('unsigned int' , 'status'))
+
+types.struct('netif_be_disconnect_t',
+ ('domid_t' , 'domid'),
+ ('unsigned int', 'netif_handle'),
+ ('unsigned int', 'status'))
+
+types.struct('netif_be_driver_status_changed_t',
+ ('unsigned int', 'status'),
+ ('unsigned int', 'nr_interfaces'))
+
+if 1 or __name__ == "__main__":
+ types.show()
--- /dev/null
+import channel
+import controller
+from messages import *
+
+class DomainControllerFactory(controller.ControllerFactory):
+ """Factory for creating domain controllers.
+ """
+
+ def createInstance(self, dom):
+ d = DomainController(self, dom)
+ self.addInstance(d)
+ return d
+
+ def getInstanceByDom(self, dom):
+ for inst in self.instances.values():
+ if inst.dom == dom:
+ return inst
+ inst = self.createInstance(dom)
+ return inst
+
+
+class DomainController(controller.Controller):
+ """Generic controller for a domain.
+ """
+
+ reasons = {'poweroff' : 'shutdown_poweroff_t',
+ 'reboot' : 'shutdown_reboot_t',
+ 'suspend' : 'shutdown_suspend_t' }
+
+ def __init__(self, factory, dom):
+ controller.Controller.__init__(self, factory, dom)
+ self.majorTypes = [ CMSG_SHUTDOWN ]
+ self.registerChannel()
+ print 'DomainController>', self, self.channel, self.idx
+
+ def shutdown(self, reason):
+ msgtype = self.reasons.get(reason)
+ if not msgtype:
+ raise ValueError('invalid reason:' + reason)
+ msg = packMsg(msgtype, {})
+ self.writeRequest(msg)
--- /dev/null
+import struct
+
+from xen.ext import xu
+
+DEBUG = 0
+
+""" All message formats.
+Added to incrementally for the various message types.
+See below.
+"""
+msg_formats = {}
+
+#============================================================================
+# Console message types.
+#============================================================================
+
+CMSG_CONSOLE = 0
+
+console_formats = { 'console_data': (CMSG_CONSOLE, 0) }
+
+msg_formats.update(console_formats)
+
+#============================================================================
+# Block interface message types.
+#============================================================================
+
+CMSG_BLKIF_BE = 1
+CMSG_BLKIF_FE = 2
+
+CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED = 0
+CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED = 32
+CMSG_BLKIF_FE_INTERFACE_CONNECT = 33
+CMSG_BLKIF_FE_INTERFACE_DISCONNECT = 34
+
+CMSG_BLKIF_BE_CREATE = 0
+CMSG_BLKIF_BE_DESTROY = 1
+CMSG_BLKIF_BE_CONNECT = 2
+CMSG_BLKIF_BE_DISCONNECT = 3
+CMSG_BLKIF_BE_VBD_CREATE = 4
+CMSG_BLKIF_BE_VBD_DESTROY = 5
+CMSG_BLKIF_BE_VBD_GROW = 6
+CMSG_BLKIF_BE_VBD_SHRINK = 7
+CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED = 32
+
+BLKIF_DRIVER_STATUS_DOWN = 0
+BLKIF_DRIVER_STATUS_UP = 1
+
+BLKIF_INTERFACE_STATUS_DESTROYED = 0 #/* Interface doesn't exist. */
+BLKIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */
+BLKIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */
+
+BLKIF_BE_STATUS_OKAY = 0
+BLKIF_BE_STATUS_ERROR = 1
+BLKIF_BE_STATUS_INTERFACE_EXISTS = 2
+BLKIF_BE_STATUS_INTERFACE_NOT_FOUND = 3
+BLKIF_BE_STATUS_INTERFACE_CONNECTED = 4
+BLKIF_BE_STATUS_VBD_EXISTS = 5
+BLKIF_BE_STATUS_VBD_NOT_FOUND = 6
+BLKIF_BE_STATUS_OUT_OF_MEMORY = 7
+BLKIF_BE_STATUS_EXTENT_NOT_FOUND = 8
+BLKIF_BE_STATUS_MAPPING_ERROR = 9
+
+blkif_formats = {
+ 'blkif_be_connect_t':
+ (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT),
+
+ 'blkif_be_create_t':
+ (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE),
+
+ 'blkif_be_disconnect_t':
+ (CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT),
+
+ 'blkif_be_destroy_t':
+ (CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY),
+
+ 'blkif_be_vbd_create_t':
+ (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE),
+
+ 'blkif_be_vbd_grow_t':
+ (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW),
+
+ 'blkif_be_vbd_destroy_t':
+ (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY),
+
+ 'blkif_fe_interface_status_changed_t':
+ (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED),
+
+ 'blkif_fe_driver_status_changed_t':
+ (CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED),
+
+ 'blkif_fe_interface_connect_t':
+ (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT),
+}
+
+msg_formats.update(blkif_formats)
+
+#============================================================================
+# Network interface message types.
+#============================================================================
+
+CMSG_NETIF_BE = 3
+CMSG_NETIF_FE = 4
+
+CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED = 0
+CMSG_NETIF_FE_DRIVER_STATUS_CHANGED = 32
+CMSG_NETIF_FE_INTERFACE_CONNECT = 33
+CMSG_NETIF_FE_INTERFACE_DISCONNECT = 34
+
+CMSG_NETIF_BE_CREATE = 0
+CMSG_NETIF_BE_DESTROY = 1
+CMSG_NETIF_BE_CONNECT = 2
+CMSG_NETIF_BE_DISCONNECT = 3
+CMSG_NETIF_BE_DRIVER_STATUS_CHANGED = 32
+
+NETIF_INTERFACE_STATUS_DESTROYED = 0 #/* Interface doesn't exist. */
+NETIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */
+NETIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */
+
+NETIF_DRIVER_STATUS_DOWN = 0
+NETIF_DRIVER_STATUS_UP = 1
+
+netif_formats = {
+ 'netif_be_connect_t':
+ (CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT),
+
+ 'netif_be_create_t':
+ (CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE),
+
+ 'netif_be_disconnect_t':
+ (CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT),
+
+ 'netif_be_destroy_t':
+ (CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY),
+
+ 'netif_be_driver_status_changed_t':
+ (CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED),
+
+ 'netif_fe_driver_status_changed_t':
+ (CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED),
+
+ 'netif_fe_interface_connect_t':
+ (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT),
+
+ 'netif_fe_interface_status_changed_t':
+ (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED),
+ }
+
+msg_formats.update(netif_formats)
+
+#============================================================================
+CMSG_SHUTDOWN = 6
+
+CMSG_SHUTDOWN_POWEROFF = 0
+CMSG_SHUTDOWN_REBOOT = 1
+CMSG_SHUTDOWN_SUSPEND = 2
+
+STOPCODE_shutdown = 0
+STOPCODE_reboot = 1
+STOPCODE_suspend = 2
+
+shutdown_formats = {
+ 'shutdown_poweroff_t':
+ (CMSG_SHUTDOWN, CMSG_SHUTDOWN_POWEROFF),
+
+ 'shutdown_reboot_t':
+ (CMSG_SHUTDOWN, CMSG_SHUTDOWN_REBOOT),
+
+ 'shutdown_suspend_t':
+ (CMSG_SHUTDOWN, CMSG_SHUTDOWN_SUSPEND),
+ }
+
+msg_formats.update(shutdown_formats)
+
+#============================================================================
+
+class Msg:
+ pass
+
+def packMsg(ty, params):
+ if DEBUG: print '>packMsg', ty, params
+ (major, minor) = msg_formats[ty]
+ args = {}
+ for (k, v) in params.items():
+ if k == 'mac':
+ for i in range(0, 6):
+ args['mac[%d]' % i] = v[i]
+ else:
+ args[k] = v
+ if DEBUG:
+ for (k, v) in args.items():
+ print 'packMsg>', k, v, type(v)
+ msgid = 0
+ msg = xu.message(major, minor, msgid, args)
+ return msg
+
+def unpackMsg(ty, msg):
+ args = msg.get_payload()
+ mac = [0, 0, 0, 0, 0, 0]
+ macs = []
+ for (k, v) in args.items():
+ if k.startswith('mac['):
+ macs += k
+ i = int(k[4:5])
+ mac[i] = v
+ else:
+ pass
+ if macs:
+ args['mac'] = mac
+ for k in macs:
+ del args[k]
+ if DEBUG: print '<unpackMsg', ty, args
+ return args
+
+def msgTypeName(ty, subty):
+ for (name, info) in msg_formats.items():
+ if info[0] == ty and info[1] == subty:
+ return name
+ return None
+
--- /dev/null
+import random
+
+from twisted.internet import defer
+
+from xen.xend import sxp
+from xen.xend import PrettyPrint
+from xen.xend import Vifctl
+
+import channel
+import controller
+from messages import *
+
+class NetifControllerFactory(controller.ControllerFactory):
+ """Factory for creating network interface controllers.
+ Also handles the 'back-end' channel to the device driver domain.
+ """
+
+ def __init__(self):
+ controller.ControllerFactory.__init__(self)
+
+ self.majorTypes = [ CMSG_NETIF_BE ]
+
+ self.subTypes = {
+ CMSG_NETIF_BE_CREATE : self.recv_be_create,
+ CMSG_NETIF_BE_CONNECT: self.recv_be_connect,
+ CMSG_NETIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
+ }
+ self.attached = 1
+ self.registerChannel()
+
+ def createInstance(self, dom, recreate=0):
+ """Create or find the network interface controller for a domain.
+ """
+ #print 'netif>createInstance> dom=', dom
+ netif = self.getInstanceByDom(dom)
+ if netif is None:
+ netif = NetifController(self, dom)
+ self.addInstance(netif)
+ return netif
+
+ def getDomainDevices(self, dom):
+ netif = self.getInstanceByDom(dom)
+ return (netif and netif.getDevices()) or []
+
+ def getDomainDevice(self, dom, vif):
+ netif = self.getInstanceByDom(dom)
+ return (netif and netif.getDevice(vif)) or None
+
+ def setControlDomain(self, dom, recreate=0):
+ """Set the 'back-end' device driver domain.
+ """
+ if self.dom == dom: return
+ self.deregisterChannel()
+ if not recreate:
+ self.attached = 0
+ self.dom = dom
+ self.registerChannel()
+ #
+ #if xend.netif.be_port.remote_dom != 0:
+ # xend.netif.recovery = True
+ # xend.netif.be_port = xend.main.port_from_dom(dom)
+ #
+
+ def getControlDomain(self):
+ return self.dom
+
+ def recv_be_create(self, msg, req):
+ self.callDeferred(0)
+
+ def recv_be_connect(self, msg, req):
+ val = unpackMsg('netif_be_connect_t', msg)
+ dom = val['domid']
+ vif = val['netif_handle']
+ netif = self.getInstanceByDom(dom)
+ if netif:
+ netif.send_interface_connected(vif)
+ else:
+ print "recv_be_connect> unknown vif=", vif
+ pass
+
+ def recv_be_driver_status_changed(self, msg, req):
+ val = unpackMsg('netif_be_driver_status_changed_t', msg)
+ status = val['status']
+ if status == NETIF_DRIVER_STATUS_UP and not self.attached:
+ # If we are not attached the driver domain was changed, and
+ # this signals the new driver domain is ready.
+ for netif in self.getInstances():
+ netif.reattach_devices()
+ self.attached = 1
+
+## pl = msg.get_payload()
+## status = pl['status']
+## if status == NETIF_DRIVER_STATUS_UP:
+## if xend.netif.recovery:
+## print "New netif backend now UP, notifying guests:"
+## for netif_key in interface.list.keys():
+## netif = interface.list[netif_key]
+## netif.create()
+## print " Notifying %d" % netif.dom
+## msg = xu.message(
+## CMSG_NETIF_FE,
+## CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0,
+## { 'handle' : 0, 'status' : 1 })
+## netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg)
+## print "Done notifying guests"
+## recovery = False
+
+class NetDev(controller.Dev):
+ """Info record for a network device.
+ """
+
+ def __init__(self, ctrl, vif, mac):
+ controller.Dev.__init__(self, ctrl)
+ self.vif = vif
+ self.mac = mac
+ self.evtchn = None
+ self.bridge = None
+ self.ipaddr = []
+
+ def sxpr(self):
+ vif = str(self.vif)
+ mac = self.get_mac()
+ val = ['netdev', ['vif', vif], ['mac', mac]]
+ if self.bridge:
+ val.append(['bridge', self.bridge])
+ if self.evtchn:
+ val.append(['evtchn',
+ self.evtchn['port1'],
+ self.evtchn['port2']])
+ return val
+
+ def get_vifname(self):
+ return "vif%d.%d" % (self.controller.dom, self.vif)
+
+ def get_mac(self):
+ return ':'.join(map(lambda x: "%x" % x, self.mac))
+
+ def vifctl_params(self):
+ return { 'mac' : self.get_mac(),
+ 'bridge': self.bridge,
+ 'ipaddr': self.ipaddr }
+
+ def up(self, bridge=None, ipaddr=[]):
+ self.bridge = bridge
+ self.ipaddr = ipaddr
+ Vifctl.up(self.get_vifname(), **self.vifctl_params())
+
+ def down(self):
+ Vifctl.down(self.get_vifname(), **self.vifctl_params())
+
+ def destroy(self):
+ def cb_destroy(val):
+ self.controller.send_be_destroy(self.vif)
+ print 'NetDev>destroy>', 'vif=', self.vif
+ PrettyPrint.prettyprint(self.sxpr())
+ self.down()
+ d = self.controller.factory.addDeferred()
+ d.addCallback(cb_destroy)
+ self.controller.send_be_disconnect(self.vif)
+ #self.controller.send_be_destroy(self.vif)
+
+
+class NetifController(controller.Controller):
+ """Network interface controller. Handles all network devices for a domain.
+ """
+
+ def __init__(self, factory, dom):
+ #print 'NetifController> dom=', dom
+ controller.Controller.__init__(self, factory, dom)
+ self.devices = {}
+
+ self.majorTypes = [ CMSG_NETIF_FE ]
+
+ self.subTypes = {
+ CMSG_NETIF_FE_DRIVER_STATUS_CHANGED:
+ self.recv_fe_driver_status_changed,
+ CMSG_NETIF_FE_INTERFACE_CONNECT :
+ self.recv_fe_interface_connect,
+ }
+ self.registerChannel()
+ #print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx
+
+ def sxpr(self):
+ val = ['netif', ['dom', self.dom]]
+ return val
+
+ def randomMAC(self):
+ # VIFs get a random MAC address with a "special" vendor id.
+ #
+ # NB. The vendor is currently an "obsolete" one that used to belong
+ # to DEC (AA-00-00). Using it is probably a bit rude :-)
+ #
+ # NB2. The first bit of the first random octet is set to zero for
+ # all dynamic MAC addresses. This may allow us to manually specify
+ # MAC addresses for some VIFs with no fear of clashes.
+ mac = [ 0xaa, 0x00, 0x00,
+ random.randint(0x00, 0x7f),
+ random.randint(0x00, 0xff),
+ random.randint(0x00, 0xff) ]
+ return mac
+
+ def lostChannel(self):
+ print 'NetifController>lostChannel>', 'dom=', self.dom
+ #self.destroyDevices()
+ controller.Controller.lostChannel(self)
+
+ def getDevices(self):
+ return self.devices.values()
+
+ def getDevice(self, vif):
+ return self.devices.get(vif)
+
+ def addDevice(self, vif, vmac):
+ if vmac is None:
+ mac = self.randomMAC()
+ else:
+ mac = [ int(x, 16) for x in vmac.split(':') ]
+ if len(mac) != 6: raise ValueError("invalid mac")
+ #print "attach_device>", "vif=", vif, "mac=", mac
+ dev = NetDev(self, vif, mac)
+ self.devices[vif] = dev
+ return dev
+
+ def destroy(self):
+ print 'NetifController>destroy>', 'dom=', self.dom
+ self.destroyDevices()
+
+ def destroyDevices(self):
+ for dev in self.getDevices():
+ dev.destroy()
+
+ def attachDevice(self, vif, vmac, recreate=0):
+ """Attach a network device.
+ If vmac is None a random mac address is assigned.
+
+ @param vif interface index
+ @param vmac mac address (string)
+ """
+ self.addDevice(vif, vmac)
+ if recreate:
+ d = defer.Deferred()
+ d.callback(self)
+ else:
+ d = self.factory.addDeferred()
+ self.send_be_create(vif)
+ return d
+
+ def reattach_devices(self):
+ """Reattach all devices when the back-end control domain has changed.
+ """
+ d = self.factory.addDeferred()
+ self.send_be_create(vif)
+ self.attach_fe_devices(0)
+
+ def attach_fe_devices(self):
+ for dev in self.devices.values():
+ msg = packMsg('netif_fe_interface_status_changed_t',
+ { 'handle' : dev.vif,
+ 'status' : NETIF_INTERFACE_STATUS_DISCONNECTED,
+ 'evtchn' : 0,
+ 'mac' : dev.mac })
+ self.writeRequest(msg)
+
+ def recv_fe_driver_status_changed(self, msg, req):
+ if not req: return
+ msg = packMsg('netif_fe_driver_status_changed_t',
+ { 'status' : NETIF_DRIVER_STATUS_UP,
+ 'nr_interfaces' : len(self.devices) })
+ self.writeRequest(msg)
+ self.attach_fe_devices()
+
+ def recv_fe_interface_connect(self, msg, req):
+ val = unpackMsg('netif_fe_interface_connect_t', msg)
+ dev = self.devices[val['handle']]
+ dev.evtchn = channel.eventChannel(0, self.dom)
+ msg = packMsg('netif_be_connect_t',
+ { 'domid' : self.dom,
+ 'netif_handle' : dev.vif,
+ 'evtchn' : dev.evtchn['port1'],
+ 'tx_shmem_frame' : val['tx_shmem_frame'],
+ 'rx_shmem_frame' : val['rx_shmem_frame'] })
+ self.factory.writeRequest(msg)
+
+ def send_interface_connected(self, vif):
+ dev = self.devices[vif]
+ msg = packMsg('netif_fe_interface_status_changed_t',
+ { 'handle' : dev.vif,
+ 'status' : NETIF_INTERFACE_STATUS_CONNECTED,
+ 'evtchn' : dev.evtchn['port2'],
+ 'mac' : dev.mac })
+ self.writeRequest(msg)
+
+ def send_be_create(self, vif):
+ dev = self.devices[vif]
+ msg = packMsg('netif_be_create_t',
+ { 'domid' : self.dom,
+ 'netif_handle' : dev.vif,
+ 'mac' : dev.mac })
+ self.factory.writeRequest(msg)
+
+ def send_be_disconnect(self, vif):
+ dev = self.devices[vif]
+ msg = packMsg('netif_be_disconnect_t',
+ { 'domid' : self.dom,
+ 'netif_handle' : dev.vif })
+ self.factory.writeRequest(msg)
+
+ def send_be_destroy(self, vif):
+ print 'NetifController>send_be_destroy>', 'dom=', self.dom, 'vif=', vif
+ PrettyPrint.prettyprint(self.sxpr())
+ dev = self.devices[vif]
+ del self.devices[vif]
+ msg = packMsg('netif_be_destroy_t',
+ { 'domid' : self.dom,
+ 'netif_handle' : vif })
+ self.factory.writeRequest(msg)
--- /dev/null
+# The following parameters could be placed in a configuration file.
+PID_FILE = '/var/run/xend.pid'
+LOG_FILE = '/var/log/xend.log'
+USER = 'root'
+CONTROL_DIR = '/var/run/xend'
+MGMT_SOCK = 'xendsock' # relative to CONTROL_DIR
+EVENT_PORT = 8001
+
+CONSOLE_PORT_BASE = 9600
+
--- /dev/null
+#!/usr/bin/python2
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+"""
+Input-driven parsing for s-expression (sxp) format.
+Create a parser: pin = Parser();
+Then call pin.input(buf) with your input.
+Call pin.input_eof() when done.
+Use pin.read() to see if a value has been parsed, pin.get_val()
+to get a parsed value. You can call ready and get_val at any time -
+you don't have to wait until after calling input_eof.
+
+"""
+from __future__ import generators
+
+import sys
+import types
+import errno
+import string
+from StringIO import StringIO
+
+__all__ = [
+ "mime_type",
+ "ParseError",
+ "Parser",
+ "atomp",
+ "show",
+ "show_xml",
+ "elementp",
+ "name",
+ "attributes",
+ "attribute",
+ "children",
+ "child",
+ "child_at",
+ "child0",
+ "child1",
+ "child2",
+ "child3",
+ "child4",
+ "child_value",
+ "has_id",
+ "with_id",
+ "child_with_id",
+ "elements",
+ "parse",
+ ]
+
+mime_type = "application/sxp"
+
+escapes = {
+ 'a': '\a',
+ 'b': '\b',
+ 't': '\t',
+ 'n': '\n',
+ 'v': '\v',
+ 'f': '\f',
+ 'r': '\r',
+ '\\': '\\',
+ '\'': '\'',
+ '\"': '\"'}
+
+k_list_open = "("
+k_list_close = ")"
+k_attr_open = "@"
+k_eval = "!"
+
+escapes_rev = {}
+for k in escapes:
+ escapes_rev[escapes[k]] = k
+
+class ParseError(StandardError):
+
+ def __init__(self, parser, value):
+ self.parser = parser
+ self.value = value
+
+ def __str__(self):
+ return self.value
+
+class ParserState:
+
+ def __init__(self, fn, parent=None):
+ self.parent = parent
+ self.buf = ''
+ self.val = []
+ self.delim = None
+ self.fn = fn
+
+ def push(self, fn):
+ return ParserState(fn, parent=self)
+
+class Parser:
+
+ def __init__(self):
+ self.error = sys.stderr
+ self.reset()
+
+ def reset(self):
+ self.val = []
+ self.eof = 0
+ self.err = 0
+ self.line_no = 0
+ self.char_no = 0
+ self.state = None
+
+ def push_state(self, fn):
+ self.state = self.state.push(fn)
+
+ def pop_state(self):
+ val = self.state
+ self.state = self.state.parent
+ if self.state and self.state.fn == self.state_start:
+ # Return to start state - produce the value.
+ self.val += self.state.val
+ self.state.val = []
+ return val
+
+ def in_class(self, c, s):
+ return s.find(c) >= 0
+
+ def in_space_class(self, c):
+ return self.in_class(c, ' \t\n\v\f\r')
+
+ def is_separator(self, c):
+ return self.in_class(c, '{}()<>[]!;')
+
+ def in_comment_class(self, c):
+ return self.in_class(c, '#')
+
+ def in_string_quote_class(self, c):
+ return self.in_class(c, '"\'')
+
+ def in_printable_class(self, c):
+ return self.in_class(c, string.printable)
+
+ def set_error_stream(self, error):
+ self.error = error
+
+ def has_error(self):
+ return self.err > 0
+
+ def at_eof(self):
+ return self.eof
+
+ def input_eof(self):
+ self.eof = 1
+ self.input_char(-1)
+
+ def input(self, buf):
+ if not buf or len(buf) == 0:
+ self.input_eof()
+ else:
+ for c in buf:
+ self.input_char(c)
+
+ def input_char(self, c):
+ if self.at_eof():
+ pass
+ elif c == '\n':
+ self.line_no += 1
+ self.char_no = 0
+ else:
+ self.char_no += 1
+
+ if self.state is None:
+ self.begin_start(None)
+ self.state.fn(c)
+
+ def ready(self):
+ return len(self.val) > 0
+
+ def get_val(self):
+ v = self.val[0]
+ self.val = self.val[1:]
+ return v
+
+ def get_all(self):
+ return self.val
+
+ def begin_start(self, c):
+ self.state = ParserState(self.state_start)
+
+ def end_start(self):
+ self.val += self.state.val
+ self.pop_state()
+
+ def state_start(self, c):
+ if self.at_eof():
+ self.end_start()
+ elif self.in_space_class(c):
+ pass
+ elif self.in_comment_class(c):
+ self.begin_comment(c)
+ elif c == k_list_open:
+ self.begin_list(c)
+ elif c == k_list_close:
+ raise ParseError(self, "syntax error: "+c)
+ elif self.in_string_quote_class(c):
+ self.begin_string(c)
+ elif self.in_printable_class(c):
+ self.begin_atom(c)
+ elif c == chr(4):
+ # ctrl-D, EOT: end-of-text.
+ self.input_eof()
+ else:
+ raise ParseError(self, "invalid character: code %d" % ord(c))
+
+ def begin_comment(self, c):
+ self.push_state(self.state_comment)
+ self.state.buf += c
+
+ def end_comment(self):
+ self.pop_state()
+
+ def state_comment(self, c):
+ if c == '\n' or self.at_eof():
+ self.end_comment()
+ else:
+ self.state.buf += c
+
+ def begin_string(self, c):
+ self.push_state(self.state_string)
+ self.state.delim = c
+
+ def end_string(self):
+ val = self.state.buf
+ self.state.parent.val.append(val)
+ self.pop_state()
+
+ def state_string(self, c):
+ if self.at_eof():
+ raise ParseError(self, "unexpected EOF")
+ elif c == self.state.delim:
+ self.end_string()
+ elif c == '\\':
+ self.push_state(self.state_escape)
+ else:
+ self.state.buf += c
+
+ def state_escape(self, c):
+ if self.at_eof():
+ raise ParseError(self, "unexpected EOF")
+ d = escapes.get(c)
+ if d:
+ self.state.parent.buf += d
+ self.pop_state()
+ elif c == 'x':
+ self.state.fn = self.state_hex
+ self.state.val = 0
+ else:
+ self.state.fn = self.state_octal
+ self.state.val = 0
+ self.input_char(c)
+
+ def state_octal(self, c):
+ def octaldigit(c):
+ self.state.val *= 8
+ self.state.val += ord(c) - ord('0')
+ self.state.buf += c
+ if self.state.val < 0 or self.state.val > 0xff:
+ raise ParseError(self, "invalid octal escape: out of range " + self.state.buf)
+ if len(self.state.buf) == 3:
+ octaldone()
+
+ def octaldone():
+ d = chr(self.state.val)
+ self.state.parent.buf += d
+ self.pop_state()
+
+ if self.at_eof():
+ raise ParseError(self, "unexpected EOF")
+ elif '0' <= c <= '7':
+ octaldigit(c)
+ elif len(self.buf):
+ octaldone()
+ self.input_char(c)
+
+ def state_hex(self, c):
+ def hexdone():
+ d = chr(self.state.val)
+ self.state.parent.buf += d
+ self.pop_state()
+
+ def hexdigit(c, d):
+ self.state.val *= 16
+ self.state.val += ord(c) - ord(d)
+ self.state.buf += c
+ if self.state.val < 0 or self.state.val > 0xff:
+ raise ParseError(self, "invalid hex escape: out of range " + self.state.buf)
+ if len(self.state.buf) == 2:
+ hexdone()
+
+ if self.at_eof():
+ raise ParseError(self, "unexpected EOF")
+ elif '0' <= c <= '9':
+ hexdigit(c, '0')
+ elif 'A' <= c <= 'F':
+ hexdigit(c, 'A')
+ elif 'a' <= c <= 'f':
+ hexdigit(c, 'a')
+ elif len(buf):
+ hexdone()
+ self.input_char(c)
+
+ def begin_atom(self, c):
+ self.push_state(self.state_atom)
+ self.state.buf = c
+
+ def end_atom(self):
+ val = self.state.buf
+ self.state.parent.val.append(val)
+ self.pop_state()
+
+ def state_atom(self, c):
+ if self.at_eof():
+ self.end_atom()
+ elif (self.is_separator(c) or
+ self.in_space_class(c) or
+ self.in_comment_class(c)):
+ self.end_atom()
+ self.input_char(c)
+ else:
+ self.state.buf += c
+
+ def begin_list(self, c):
+ self.push_state(self.state_list)
+
+ def end_list(self):
+ val = self.state.val
+ self.state.parent.val.append(val)
+ self.pop_state()
+
+ def state_list(self, c):
+ if self.at_eof():
+ raise ParseError(self, "unexpected EOF")
+ elif c == k_list_close:
+ self.end_list()
+ else:
+ self.state_start(c)
+
+def atomp(sxpr):
+ if sxpr.isalnum() or sxpr == '@':
+ return 1
+ for c in sxpr:
+ if c in string.whitespace: return 0
+ if c in '"\'\\(){}[]<>$#&%^': return 0
+ if c in string.ascii_letters: continue
+ if c in string.digits: continue
+ if c in '.-_:/~': continue
+ return 0
+ return 1
+
+def show(sxpr, out=sys.stdout):
+ if isinstance(sxpr, types.ListType):
+ out.write(k_list_open)
+ i = 0
+ for x in sxpr:
+ if i: out.write(' ')
+ show(x, out)
+ i += 1
+ out.write(k_list_close)
+ elif isinstance(sxpr, types.StringType) and atomp(sxpr):
+ out.write(sxpr)
+ else:
+ #out.write("'" + str(sxpr) + "'")
+ out.write(repr(str(sxpr)))
+
+def show_xml(sxpr, out=sys.stdout):
+ if isinstance(sxpr, types.ListType):
+ element = name(sxpr)
+ out.write('<%s' % element)
+ for attr in attributes(sxpr):
+ out.write(' %s=%s' % (attr[0], attr[1]))
+ out.write('>')
+ i = 0
+ for x in children(sxpr):
+ if i: out.write(' ')
+ show_xml(x, out)
+ i += 1
+ out.write('</%s>' % element)
+ elif isinstance(sxpr, types.StringType) and atomp(sxpr):
+ out.write(sxpr)
+ else:
+ out.write(str(sxpr))
+
+def elementp(sxpr, elt=None):
+ return (isinstance(sxpr, types.ListType)
+ and len(sxpr)
+ and (None == elt or sxpr[0] == elt))
+
+def name(sxpr):
+ val = None
+ if isinstance(sxpr, types.StringType):
+ val = sxpr
+ elif isinstance(sxpr, types.ListType) and len(sxpr):
+ val = sxpr[0]
+ return val
+
+def attributes(sxpr):
+ val = []
+ if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
+ attr = sxpr[1]
+ if elementp(attr, k_attr_open):
+ val = attr[1:]
+ return val
+
+def attribute(sxpr, key, val=None):
+ for x in attributes(sxpr):
+ if x[0] == key:
+ val = x[1]
+ break
+ return val
+
+def children(sxpr, elt=None):
+ val = []
+ if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
+ i = 1
+ x = sxpr[i]
+ if elementp(x, k_attr_open):
+ i += 1
+ val = sxpr[i : ]
+ if elt:
+ def iselt(x):
+ return elementp(x, elt)
+ val = filter(iselt, val)
+ return val
+
+def child(sxpr, elt, val=None):
+ for x in children(sxpr):
+ if elementp(x, elt):
+ val = x
+ break
+ return val
+
+def child_at(sxpr, index, val=None):
+ kids = children(sxpr)
+ if len(kids) > index:
+ val = kids[index]
+ return val
+
+def child0(sxpr, val=None):
+ return child_at(sxpr, 0, val)
+
+def child1(sxpr, val=None):
+ return child_at(sxpr, 1, val)
+
+def child2(sxpr, val=None):
+ return child_at(sxpr, 2, val)
+
+def child3(sxpr, val=None):
+ return child_at(sxpr, 3, val)
+
+def child4(sxpr, val=None):
+ return child_at(sxpr, 4, val)
+
+def child_value(sxpr, elt, val=None):
+ kid = child(sxpr, elt)
+ if kid:
+ val = child_at(kid, 0, val)
+ return val
+
+def has_id(sxpr, id):
+ """Test if an s-expression has a given id.
+ """
+ return attribute(sxpr, 'id') == id
+
+def with_id(sxpr, id, val=None):
+ """Find the first s-expression with a given id, at any depth.
+
+ sxpr s-exp or list
+ id id
+ val value if not found (default None)
+
+ return s-exp or val
+ """
+ if isinstance(sxpr, types.ListType):
+ for n in sxpr:
+ if has_id(n, id):
+ val = n
+ break
+ v = with_id(n, id)
+ if v is None: continue
+ val = v
+ break
+ return val
+
+def child_with_id(sxpr, id, val=None):
+ """Find the first child with a given id.
+
+ sxpr s-exp or list
+ id id
+ val value if not found (default None)
+
+ return s-exp or val
+ """
+ if isinstance(sxpr, types.ListType):
+ for n in sxpr:
+ if has_id(n, id):
+ val = n
+ break
+ return val
+
+def elements(sxpr, ctxt=None):
+ """Generate elements (at any depth).
+ Visit elements in pre-order.
+ Values generated are (node, context)
+ The context is None if there is no parent, otherwise
+ (index, parent, context) where index is the node's index w.r.t its parent,
+ and context is the parent's context.
+
+ sxpr s-exp
+
+ returns generator
+ """
+ yield (sxpr, ctxt)
+ i = 0
+ for n in children(sxpr):
+ if isinstance(n, types.ListType):
+ # Calling elements() recursively does not generate recursively,
+ # it just returns a generator object. So we must iterate over it.
+ for v in elements(n, (i, sxpr, ctxt)):
+ yield v
+ i += 1
+
+def to_string(sxpr):
+ """Convert an sxpr to a string.
+
+ sxpr sxpr
+ returns string
+ """
+ io = StringIO()
+ show(sxpr, io)
+ io.seek(0)
+ val = io.getvalue()
+ io.close()
+ return val
+
+def from_string(str):
+ """Create an sxpr by parsing a string.
+
+ str string
+ returns sxpr
+ """
+ io = StringIO(str)
+ return parse(io)
+
+def parse(io):
+ """Completely parse all input from 'io'.
+
+ io input file object
+ returns list of values, None if incomplete
+ raises ParseError on parse error
+ """
+ pin = Parser()
+ while 1:
+ buf = io.readline()
+ pin.input(buf)
+ if len(buf) == 0:
+ break
+ if pin.ready():
+ val = pin.get_all()
+ else:
+ val = None
+ return val
+
+
+if __name__ == '__main__':
+ print ">main"
+ pin = Parser()
+ while 1:
+ buf = sys.stdin.read(1024)
+ #buf = sys.stdin.readline()
+ pin.input(buf)
+ while pin.ready():
+ val = pin.get_val()
+ print
+ print '****** val=', val
+ if len(buf) == 0:
+ break
+
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+"""Domain creation.
+"""
+import string
+import sys
+
+from xen.xend import sxp
+from xen.xend import PrettyPrint
+from xen.xend.XendClient import server
+
+from xen.xm.opts import *
+
+gopts = Opts(use="""[options]
+
+Create a domain.
+""")
+
+gopts.opt('help', short='h',
+ fn=set_true, default=0,
+ use="Print this help.")
+
+gopts.opt('quiet', short='q',
+ fn=set_true, default=0,
+ use="Quiet.")
+
+gopts.opt('path', val='PATH',
+ fn=set_value, default='.:/etc/xen',
+ use="Search path for default scripts.")
+
+gopts.opt('defaults', short='f', val='FILE',
+ fn=set_value, default='xmdefaults',
+ use="Use the given default script.")
+
+gopts.opt('config', short='F', val='FILE',
+ fn=set_value, default=None,
+ use='Domain configuration to use (SXP).')
+
+gopts.opt('load', short='L', val='FILE',
+ fn=set_value, default=None,
+ use='Domain saved state to load.')
+
+gopts.opt('define', short='D', val='VAR=VAL',
+ fn=set_var, default=None,
+ use="""Set a variable before loading defaults, e.g. '-D vmid=3'
+ to set vmid. May be repeated to set more thanone variable.""")
+
+gopts.opt('dryrun', short='n',
+ fn=set_true, default=0,
+ use="Dry run - print the config but don't create the domain.")
+
+gopts.opt('name', short='N', val='NAME',
+ fn=set_value, default=None,
+ use="Domain name.")
+
+gopts.opt('console', short='c',
+ fn=set_true, default=0,
+ use="Connect to console after domain is created.")
+
+gopts.opt('kernel', short='k', val='FILE',
+ fn=set_value, default=None,
+ use="Path to kernel image.")
+
+gopts.opt('ramdisk', short='r', val='FILE',
+ fn=set_value, default='',
+ use="Path to ramdisk.")
+
+gopts.opt('builder', short='b', val='FUNCTION',
+ fn=set_value, default='linux',
+ use="Function to use to build the domain.")
+
+gopts.opt('memory', short='m', val='MEMORY',
+ fn=set_value, default=128,
+ use="Domain memory in MB.")
+
+gopts.opt('blkif',
+ fn=set_true, default=0,
+ use="Make the domain a block device backend.")
+
+gopts.opt('netif',
+ fn=set_true, default=0,
+ use="Make the domain a network interface backend.")
+
+gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE',
+ fn=append_value, default=[],
+ use="""Add a disk device to a domain. The physical device is DEV, which
+ is exported to the domain as VDEV. The disk is read-only if MODE
+ is 'r', read-write if MODE is 'w'.
+ The option may be repeated to add more than one disk.
+ """)
+
+gopts.opt('pci', val='BUS,DEV,FUNC',
+ fn=append_value, default=[],
+ use="""Add a PCI device to a domain, using given params (in hex).
+ For example '-pci c0,02,1a'.
+ The option may be repeated to add more than one pci device.
+ """)
+
+gopts.opt('ipaddr', short='i', val="IPADDR",
+ fn=append_value, default=[],
+ use="Add an IP address to the domain.")
+
+gopts.opt('vif', val="mac=MAC,bridge=BRIDGE",
+ fn=append_value, default=[],
+ use="""Add a network interface with the given MAC address and bridge.
+ If mac is not specified a random MAC address is used.
+ If bridge is not specified the default bridge is used.
+ This option may be repeated to add more than one vif.
+ Specifying vifs will increase the number of interfaces as needed.
+ """)
+
+gopts.opt('nics', val="NUM",
+ fn=set_int, default=1,
+ use="""Set the number of network interfaces.
+ Use the vif option to define interface parameters, otherwise
+ defaults are used. Specifying vifs will increase the
+ number of interfaces as needed.
+ """)
+
+gopts.opt('root', short='R', val='DEVICE',
+ fn=set_value, default='',
+ use="""Set the root= parameter on the kernel command line.
+ Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
+
+gopts.opt('extra', short='E', val="ARGS",
+ fn=set_value, default='',
+ use="Set extra arguments to append to the kernel command line.")
+
+gopts.opt('ip', short='I', val='IPADDR',
+ fn=set_value, default='',
+ use="Set the kernel IP interface address.")
+
+gopts.opt('gateway', val="IPADDR",
+ fn=set_value, default='',
+ use="Set the kernel IP gateway.")
+
+gopts.opt('netmask', val="MASK",
+ fn=set_value, default = '',
+ use="Set the kernel IP netmask.")
+
+gopts.opt('hostname', val="NAME",
+ fn=set_value, default='',
+ use="Set the kernel IP hostname.")
+
+gopts.opt('interface', val="INTF",
+ fn=set_value, default="eth0",
+ use="Set the kernel IP interface name.")
+
+gopts.opt('dhcp', val="off|dhcp",
+ fn=set_value, default='off',
+ use="Set the kernel dhcp option.")
+
+gopts.opt('nfs_server', val="IPADDR",
+ fn=set_value, default=None,
+ use="Set the address of the NFS server for NFS root.")
+
+gopts.opt('nfs_root', val="PATH",
+ fn=set_value, default=None,
+ use="Set the path of the root NFS directory.")
+
+def strip(pre, s):
+ """Strip prefix 'pre' if present.
+ """
+ if s.startswith(pre):
+ return s[len(pre):]
+ else:
+ return s
+
+def configure_image(config, opts):
+ """Create the image config.
+ """
+ config_image = [ opts.builder ]
+ config_image.append([ 'kernel', os.path.abspath(opts.kernel) ])
+ if opts.ramdisk:
+ config_image.append([ 'ramdisk', os.path.abspath(opts.ramdisk) ])
+ if opts.cmdline_ip:
+ cmdline_ip = strip('ip=', opts.cmdline_ip)
+ config_image.append(['ip', cmdline_ip])
+ if opts.root:
+ cmdline_root = strip('root=', opts.root)
+ config_image.append(['root', cmdline_root])
+ if opts.extra:
+ config_image.append(['args', opts.extra])
+ config.append(['image', config_image ])
+
+def configure_disks(config_devs, opts):
+ """Create the config for disks (virtual block devices).
+ """
+ for (uname, dev, mode) in opts.disk:
+ config_vbd = ['vbd',
+ ['uname', uname],
+ ['dev', dev ],
+ ['mode', mode ] ]
+ config_devs.append(['device', config_vbd])
+
+def configure_pci(config_devs, opts):
+ """Create the config for pci devices.
+ """
+ for (bus, dev, func) in opts.pci:
+ config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
+ config_devs.append(['device', config_pci])
+
+def configure_vifs(config_devs, opts):
+ """Create the config for virtual network interfaces.
+ """
+ vifs = opts.vif
+ vifs_n = max(opts.nics, len(vifs))
+
+ for idx in range(0, vifs_n):
+ if idx < len(vifs):
+ d = vifs[idx]
+ mac = d.get('mac')
+ bridge = d.get('bridge')
+ else:
+ mac = None
+ bridge = None
+ config_vif = ['vif']
+ if mac:
+ config_vif.append(['mac', mac])
+ if bridge:
+ config_vif.append(['bridge', bridge])
+ config_devs.append(['device', config_vif])
+
+def configure_vfr(config, opts):
+ if not opts.ipaddr: return
+ config_vfr = ['vfr']
+ idx = 0 # No way of saying which IP is for which vif?
+ for ip in opts.ipaddr:
+ config_vfr.append(['vif', ['id', idx], ['ip', ip]])
+ config.append(config_vfr)
+
+
+def make_config(opts):
+ """Create the domain configuration.
+ """
+
+ config = ['vm',
+ ['name', opts.name ],
+ ['memory', opts.memory ] ]
+ if opts.cpu:
+ config.append(['cpu', opts.cpu])
+ if opts.blkif:
+ config.append(['backend', ['blkif']])
+ if opts.netif:
+ config.append(['backend', ['netif']])
+
+ configure_image(config, opts)
+ config_devs = []
+ configure_disks(config_devs, opts)
+ configure_pci(config_devs, opts)
+ configure_vifs(config_devs, opts)
+ config += config_devs
+ return config
+
+def preprocess_disk(opts):
+ if not opts.disk: return
+ disk = []
+ for v in opts.disk:
+ d = v.split(',')
+ if len(d) != 3:
+ opts.err('Invalid disk specifier: ' + v)
+ disk.append(d)
+ opts.disk = disk
+
+def preprocess_pci(opts):
+ if not opts.pci: return
+ pci = []
+ for v in opts.pci:
+ d = v.split(',')
+ if len(d) != 3:
+ opts.err('Invalid pci specifier: ' + v)
+ # Components are in hex: add hex specifier.
+ hexd = map(lambda v: '0x'+v, d)
+ pci.append(hexd)
+ opts.pci = pci
+
+def preprocess_vifs(opts):
+ if not opts.vif: return
+ vifs = []
+ for vif in opts.vif:
+ d = {}
+ a = vif.split(',')
+ for b in a:
+ (k, v) = b.strip().split('=')
+ k = k.strip()
+ v = v.strip()
+ if k not in ['mac', 'bridge']:
+ opts.err('Invalid vif specifier: ' + vif)
+ d[k] = v
+ vifs.append(d)
+ opts.vif = vifs
+
+def preprocess_ip(opts):
+ setip = (opts.hostname or opts.netmask
+ or opts.gateway or opts.dhcp or opts.interface)
+ if not setip: return
+ #if not opts
+ ip = (opts.ip
+ + ':'
+ + ':' + opts.gateway
+ + ':' + opts.netmask
+ + ':' + opts.hostname
+ + ':' + opts.interface
+ + ':' + opts.dhcp)
+ opts.cmdline_ip = ip
+
+def preprocess_nfs(opts):
+ if (opts.nfs_root or opts.nfs_server):
+ if (not opts.nfs_root) or (not opts.nfs_server):
+ opts.err('Must set nfs root and nfs server')
+ else:
+ return
+ nfs = 'nfsroot=' + opts.nfs_server + ':' + opts.nfs_root
+ opts.extra = nfs + ' ' + opts.extra
+
+def preprocess(opts):
+ if not opts.kernel:
+ opts.err("No kernel specified")
+ preprocess_disk(opts)
+ preprocess_pci(opts)
+ preprocess_vifs(opts)
+ preprocess_ip(opts)
+ preprocess_nfs(opts)
+
+def make_domain(opts, config):
+ """Create, build and start a domain.
+ Returns: [int] the ID of the new domain.
+ """
+ if opts.vals.load:
+ filename = os.path.abspath(opts.vals.load)
+ dominfo = server.xend_domain_restore(filename, config)
+ else:
+ dominfo = server.xend_domain_create(config)
+
+ dom = int(sxp.child_value(dominfo, 'id'))
+ console_info = sxp.child(dominfo, 'console')
+ if console_info:
+ console_port = int(sxp.child_value(console_info, 'port'))
+ else:
+ console_port = None
+
+ if server.xend_domain_unpause(dom) < 0:
+ server.xend_domain_destroy(dom)
+ opts.err("Failed to start domain %d" % dom)
+ opts.info("Started domain %d, console on port %d"
+ % (dom, console_port))
+ return (dom, console_port)
+
+def main(argv):
+ opts = gopts
+ args = opts.parse(argv)
+ if opts.vals.help:
+ opts.usage()
+ return
+ if opts.vals.config:
+ pass
+ else:
+ opts.load_defaults()
+ preprocess(opts.vals)
+ config = make_config(opts.vals)
+ if opts.vals.dryrun:
+ PrettyPrint.prettyprint(config)
+ else:
+ make_domain(opts, config)
+
+if __name__ == '__main__':
+ main(sys.argv)
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+"""Grand unified management application for Xen.
+"""
+import os
+import os.path
+import sys
+from getopt import getopt
+
+from xen.xend import PrettyPrint
+from xen.xend import sxp
+from xen.xend.XendClient import server
+from xen.xm import create, shutdown
+
+class Prog:
+ """Base class for sub-programs.
+ """
+
+ """Program group it belongs to"""
+ group = 'all'
+ """Program name."""
+ name = '??'
+ """Short program info."""
+ info = ''
+
+ def __init__(self, xm):
+ self.xm = xm
+
+ def err(self, msg):
+ self.xm.err(msg)
+
+ def help(self, args):
+ self.shortHelp(args)
+
+ def shortHelp(self, args):
+ print "%-14s %s" % (self.name, self.info)
+
+ def main(self, args):
+ """Program main entry point.
+ """
+ pass
+
+
+class ProgUnknown(Prog):
+
+ name = 'unknown'
+ info = ''
+
+ def help(self, args):
+ self.xm.err("Unknown command: %s\nTry '%s help' for more information."
+ % (args[0], self.xm.name))
+
+ main = help
+
+class Xm:
+ """Main application.
+ """
+
+ def __init__(self):
+ self.name = 'xm'
+ self.unknown = ProgUnknown(self)
+ self.progs = {}
+
+ def err(self, msg):
+ print >>sys.stderr, "Error:", msg
+ sys.exit(1)
+
+ def main(self, args):
+ """Main entry point. Dispatches to the progs.
+ """
+ self.name = args[0]
+ if len(args) < 2:
+ self.err("Missing command\nTry '%s help' for more information."
+ % self.name)
+ help = self.helparg(args)
+ p = self.getprog(args[1], self.unknown)
+ if help:
+ p.help(args[1:])
+ else:
+ p.main(args[1:])
+
+ def helparg(self, args):
+ for a in args:
+ if a in ['-h', '--help']:
+ return 1
+ return 0
+
+ def prog(self, pklass):
+ """Add a sub-program.
+
+ pklass program class (Prog subclass)
+ """
+ p = pklass(self)
+ self.progs[p.name] = p
+ return p
+
+ def getprog(self, name, val=None):
+ """Get a sub-program.
+ """
+ return self.progs.get(name, val)
+
+ def proglist(self):
+ """Get a list of sub-programs, ordered by group.
+ """
+ groups = {}
+ for p in self.progs.values():
+ l = groups.get(p.group, [])
+ l.append(p)
+ groups[p.group] = l
+ kl = groups.keys()
+ kl.sort()
+ pl = []
+ for k in kl:
+ l = groups[k]
+ l.sort()
+ pl += l
+ return pl
+
+# Create the application object, then add the sub-program classes.
+xm = Xm()
+
+class ProgHelp(Prog):
+
+ name = "help"
+ info = "Print help."
+
+ def help(self, args):
+ if len(args) == 2:
+ name = args[1]
+ p = self.xm.getprog(name)
+ if p:
+ p.help(args[1:])
+ else:
+ print '%s: Unknown command: %s' % (self.name, name)
+ else:
+ for p in self.xm.proglist():
+ p.shortHelp(args)
+ print "\nTry '%s help CMD' for help on CMD" % self.xm.name
+
+ main = help
+
+xm.prog(ProgHelp)
+
+class ProgCreate(Prog):
+
+ group = 'domain'
+ name = "create"
+ info = """Create a domain."""
+
+ def help(self, args):
+ create.main([args[0], '-h'])
+
+ def main(self, args):
+ create.main(args)
+
+xm.prog(ProgCreate)
+
+class ProgSave(Prog):
+ group = 'domain'
+ name = "save"
+ info = """Save domain state (and config) to file."""
+
+ def help(self, args):
+ print args[0], "DOM FILE"
+ print """\nSave domain with id DOM to FILE."""
+
+ def main(self, args):
+ if len(args) < 3: self.err("%s: Missing arguments" % args[0])
+ dom = args[1]
+ savefile = os.path.abspath(args[2])
+ server.xend_domain_save(dom, savefile)
+
+xm.prog(ProgSave)
+
+class ProgRestore(Prog):
+ group = 'domain'
+ name = "restore"
+ info = """Create a domain from a saved state."""
+
+ def help(self, args):
+ print args[0], "FILE [CONFIG]"
+ print "\nRestore a domain from FILE using configuration CONFIG."
+
+ def main(self, help, args):
+ if len(args) < 2: self.err("%s: Missing arguments" % args[0])
+ savefile = os.path.abspath(args[1])
+ if len(args) >= 3:
+ configfile = os.path.abspath(args[2])
+ else:
+ configfile = None
+ info = server.xend_domain_restore(savefile, configfile)
+ PrettyPrint.prettyprint(info)
+
+xm.prog(ProgRestore)
+
+class ProgList(Prog):
+ group = 'domain'
+ name = "list"
+ info = """List info about domains."""
+
+ short_options = 'l'
+ long_options = ['long']
+
+ def help(self, args):
+ if help:
+ print args[0], '[options] [DOM...]'
+ print """\nGet information about domains.
+ Either all domains or the domains given.
+
+ -l, --long Get more detailed information.
+ """
+ return
+
+ def main(self, args):
+ use_long = 0
+ (options, params) = getopt(args[1:],
+ self.short_options,
+ self.long_options)
+ n = len(params)
+ for (k, v) in options:
+ if k in ['-l', '--long']:
+ use_long = 1
+
+ if n == 0:
+ doms = map(int, server.xend_domains())
+ doms.sort()
+ else:
+ doms = map(int, params)
+
+ if use_long:
+ self.long_list(doms)
+ else:
+ self.brief_list(doms)
+
+ def brief_list(self, doms):
+ print 'Dom Name Mem(MB) CPU State Time(s)'
+ for dom in doms:
+ info = server.xend_domain(dom)
+ d = {}
+ d['dom'] = int(dom)
+ d['name'] = sxp.child_value(info, 'name', '??')
+ d['mem'] = int(sxp.child_value(info, 'memory', '0'))
+ d['cpu'] = int(sxp.child_value(info, 'cpu', '0'))
+ d['state'] = sxp.child_value(info, 'state', '??')
+ d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
+ print ("%(dom)-4d %(name)-16s %(mem)7d %(cpu)3d %(state)5s %(cpu_time)7.1f" % d)
+
+ def long_list(self, doms):
+ for dom in doms:
+ info = server.xend_domain(dom)
+ print '\nDomain %d' % dom
+ PrettyPrint.prettyprint(info)
+
+xm.prog(ProgList)
+
+class ProgDestroy(Prog):
+ group = 'domain'
+ name = "destroy"
+ info = """Terminate a domain immediately."""
+
+ def help(self, args):
+ print args[0], 'DOM'
+ print '\nTerminate domain DOM immediately.'
+
+ def main(self, args):
+ if len(args) < 2: self.err("%s: Missing domain" % args[0])
+ dom = args[1]
+ server.xend_domain_destroy(dom)
+
+xm.prog(ProgDestroy)
+
+class ProgShutdown(Prog):
+ group = 'domain'
+ name = "shutdown"
+ info = """Shutdown a domain."""
+
+ def help(self, args):
+ shutdown.main([args[0], '-h'])
+
+ def main(self, args):
+ shutdown.main(args)
+
+xm.prog(ProgShutdown)
+
+class ProgPause(Prog):
+ group = 'domain'
+ name = "pause"
+ info = """Pause execution of a domain."""
+
+ def help(self, args):
+ print args[0], 'DOM'
+ print '\nPause execution of domain DOM.'
+
+ def main(self, args):
+ if len(args) < 2: self.err("%s: Missing domain" % args[0])
+ dom = args[1]
+ server.xend_domain_pause(dom)
+
+xm.prog(ProgPause)
+
+class ProgUnpause(Prog):
+ group = 'domain'
+ name = "unpause"
+ info = """Unpause a paused domain."""
+
+ def help(self, args):
+ print args[0], 'DOM'
+ print '\nUnpause execution of domain DOM.'
+
+ def main(self, args):
+ if len(args) < 2: self.err("%s: Missing domain" % args[0])
+ dom = args[1]
+ server.xend_domain_unpause(dom)
+
+xm.prog(ProgUnpause)
+
+class ProgPincpu(Prog):
+ group = 'domain'
+ name = "pincpu"
+ info = """Pin a domain to a cpu. """
+
+ def help(self, args):
+ print args[0],'DOM CPU'
+ print '\nPin domain DOM to cpu CPU.'
+
+ def main(self, args):
+ if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
+ v = map(int, args[1:3])
+ server.xend_domain_pincpu(*v)
+
+xm.prog(ProgPincpu)
+
+class ProgBvt(Prog):
+ group = 'scheduler'
+ name = "bvt"
+ info = """Set BVT scheduler parameters."""
+
+ def help(self, args):
+ print args[0], "DOM MCUADV WARP WARPL WARPU"
+ print '\nSet Borrowed Virtual Time scheduler parameters.'
+
+ def main(self, args):
+ if len(args) != 6: self.err("%s: Invalid argument(s)" % args[0])
+ v = map(int, args[1:6])
+ server.xend_domain_cpu_bvt_set(*v)
+
+xm.prog(ProgBvt)
+
+class ProgBvtslice(Prog):
+ group = 'scheduler'
+ name = "bvtslice"
+ info = """Set the BVT scheduler slice."""
+
+ def help(self, args):
+ print args[0], 'SLICE'
+ print '\nSet Borrowed Virtual Time scheduler slice.'
+
+ def main(self, args):
+ if len(args) < 2: self.err('%s: Missing slice' % args[0])
+ server.xend_node_cpu_bvt_slice_set(slice)
+
+xm.prog(ProgBvtslice)
+
+class ProgAtropos(Prog):
+ group = 'scheduler'
+ name= "atropos"
+ info = """Set atropos parameters."""
+
+ def help(self, args):
+ print args[0], "DOM PERIOD SLICE LATENCY XTRATIME"
+ print "\nSet atropos parameters."
+
+ def main(self, args):
+ if len(args) != 5: self.err("%s: Invalid argument(s)" % args[0])
+ v = map(int, args[1:5])
+ server.xend_domain_cpu_atropos_set(*v)
+
+xm.prog(ProgAtropos)
+
+class ProgRrobin(Prog):
+ group = 'scheduler'
+ name = "rrobin"
+ info = """Set round robin slice."""
+
+ def help(self, args):
+ print args[0], "SLICE"
+ print "\nSet round robin scheduler slice."
+
+ def main(self, args):
+ if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
+ rrslice = int(args[1])
+ server.xend_node_rrobin_set(rrslice)
+
+xm.prog(ProgRrobin)
+
+class ProgInfo(Prog):
+ group = 'host'
+ name = "info"
+ info = """Get information about the xen host."""
+
+ def main(self, args):
+ info = server.xend_node()
+ for x in info[1:]:
+ print "%-23s:" % x[0], x[1]
+
+xm.prog(ProgInfo)
+
+class ProgConsoles(Prog):
+ group = 'console'
+ name = "consoles"
+ info = """Get information about domain consoles."""
+
+ def main(self, args):
+ l = server.xend_consoles()
+ print "Dom Port Id"
+ for x in l:
+ info = server.xend_console(x)
+ d = {}
+ d['dom'] = sxp.child(info, 'dst', ['dst', '?', '?'])[1]
+ d['port'] = sxp.child_value(info, 'port', '?')
+ d['id'] = sxp.child_value(info, 'id', '?')
+ print "%(dom)3s %(port)4s %(id)3s" % d
+
+xm.prog(ProgConsoles)
+
+class ProgConsole(Prog):
+ group = 'console'
+ name = "console"
+ info = """Open a console to a domain."""
+
+ def help(self, args):
+ print "console DOM"
+ print "\nOpen a console to domain DOM."
+
+ def main(self, args):
+ if len(args) < 2: self.err("%s: Missing domain" % args[0])
+ dom = args[1]
+ info = server.xend_domain(dom)
+ console = sxp.child(info, "console")
+ if not console:
+ self.err("No console information")
+ port = sxp.child_value(console, "port")
+ from xen.util import console_client
+ console_client.connect("localhost", int(port))
+
+xm.prog(ProgConsole)
+
+def main(args):
+ xm.main(args)
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+"""Object-oriented command-line option support.
+"""
+from getopt import getopt
+import os
+import os.path
+import sys
+import types
+
+class Opt:
+ """An individual option.
+ """
+ def __init__(self, opts, name, short=None, long=None,
+ val=None, fn=None, use=None, default=None):
+ """Create an option.
+
+ opts parent options object
+ name name of the field it controls
+ short short (1-char) command line switch (optional)
+ long long command-line switch. Defaults to option name.
+ val string used to print option args in help.
+ If val is not specified the option has no arg.
+ fn function to call when the option is specified.
+ use usage (help) string
+ default default value if not specified on command-line
+ """
+ self.opts = opts
+ self.name = name
+ self.short = short
+ if long is None:
+ long = name
+ self.long = long
+ self.val = val
+ self.use = use
+ self.default = default
+ self.optkeys = []
+ if self.short:
+ self.optkeys.append('-' + self.short)
+ if self.long:
+ self.optkeys.append('--' + self.long)
+ self.fn = fn
+ self.specified_opt = None
+ self.specified_val = None
+ self.value = None
+ self.set(default)
+
+ def __repr__(self):
+ return self.name + '=' + str(self.specified_val)
+
+ __str__ = __repr__
+
+ def set(self, value):
+ """Set the option value.
+ """
+ self.opts.setopt(self.name, value)
+
+ def get(self):
+ """Get the option value.
+ """
+ return self.opts.getopt(self.name)
+
+ def append(self, value):
+ """Append a value to the option value.
+ """
+ v = self.get() or []
+ v.append(value)
+ self.set(v)
+
+ def short_opt(self):
+ """Short option spec.
+ """
+ if self.short:
+ if self.val:
+ return self.short + ':'
+ else:
+ return self.short
+ else:
+ return None
+
+ def long_opt(self):
+ """Long option spec.
+ """
+ if self.long:
+ if self.val:
+ return self.long + '='
+ else:
+ return self.long
+ else:
+ return None
+
+ def show(self):
+ sep = ''
+ for x in self.optkeys:
+ print sep, x,
+ sep = ','
+ if self.val:
+ print self.val,
+ print
+ if self.use:
+ print '\t',
+ print self.use
+ if self.val:
+ print '\tDefault', self.default or 'None'
+
+ def specify(self, k, v):
+ """Specify the option. Called when the option is set
+ from the command line.
+
+ k option switch used
+ v optional value given (if any)
+ """
+ if k in self.optkeys:
+ if self.val is None and v:
+ self.opts.err("Option '%s' does not take a value" % k)
+ self.specified_opt = k
+ self.specified_val = v
+ if self.fn:
+ self.fn(self, k, v)
+ return 1
+ else:
+ return 0
+
+ def specified(self):
+ """Test whether the option has been specified: set
+ from the command line.
+ """
+ return self.specified_opt
+
+class OptVals:
+ """Class to hold option values.
+ """
+ pass
+
+class Opts:
+ """Container for options.
+ """
+ def __init__(self, use=None):
+ """Options constructor.
+
+ use usage string
+ """
+ self.use = use
+ # List of options.
+ self.options = []
+ # Options indexed by name.
+ self.options_map = {}
+ # Command-line arguments.
+ self.argv = []
+ # Option values.
+ self.vals = OptVals()
+ self.vals.quiet = 0
+ # Variables for default scripts.
+ self.vars = {}
+
+ def __repr__(self):
+ return '\n'.join(map(str, self.options))
+
+ __str__ = __repr__
+
+ def opt(self, name, **args):
+ """Add an option.
+
+ name option name
+ **args keyword params for option constructor
+ """
+ x = Opt(self, name, **args)
+ self.options.append(x)
+ self.options_map[name] = x
+ return x
+
+ def setvar(self, var, val):
+ """Set a default script variable.
+ """
+ self.vars[var] = val
+
+ def getvar(self, var):
+ """Get a default script variable.
+ """
+ return self.vars.get(var)
+
+ def option(self, name):
+ """Get an option (object).
+ """
+ return self.options_map.get(name)
+
+ def setopt(self, name, val):
+ """Set an option value.
+ An option can also be set using 'opts.vals.name = val'.
+ """
+ setattr(self.vals, name, val)
+
+ def getopt(self, name):
+ """Get an option value.
+ An option value can also be got using 'opts.vals.name'.
+ """
+ getattr(self.vals, name)
+
+ def specified(self, name):
+ """Test if an option has been specified.
+ """
+ opt = self.option(name)
+ return opt and opt.specified()
+
+ def err(self, msg):
+ """Print an error to stderr and exit.
+ """
+ print >>sys.stderr, "Error:", msg
+ sys.exit(1)
+
+ def info(self, msg):
+ """Print a message to stdout (unless quiet is set).
+ """
+ if self.vals.quiet: return
+ print msg
+
+ def warn(self, msg):
+ """Print a warning to stdout.
+ """
+ print >>sys.stderr, "Warning:", msg
+
+ def parse(self, argv):
+ """Parse arguments argv using the options.
+
+ return remaining arguments
+ """
+ self.argv = argv
+ (vals, args) = getopt(argv[1:], self.short_opts(), self.long_opts())
+ self.args = args
+ for (k, v) in vals:
+ for opt in self.options:
+ if opt.specify(k, v): break
+ else:
+ print >>sys.stderr, "Error: Unknown option:", k
+ self.usage()
+ return args
+
+ def short_opts(self):
+ """Get short options specifier for getopt.
+ """
+ l = []
+ for x in self.options:
+ y = x.short_opt()
+ if not y: continue
+ l.append(y)
+ return ''.join(l)
+
+ def long_opts(self):
+ """Get long options specifier for getopt.
+ """
+ l = []
+ for x in self.options:
+ y = x.long_opt()
+ if not y: continue
+ l.append(y)
+ return l
+
+ def usage(self):
+ print 'Usage: ', self.argv[0], self.use or 'OPTIONS'
+ for opt in self.options:
+ opt.show()
+
+ def load_defaults(self):
+ """Load a defaults script. Assumes these options set:
+ 'path' search path
+ 'default' script name
+ """
+ for x in [ '' ] + self.vals.path.split(':'):
+ if x:
+ p = os.path.join(x, self.vals.defaults)
+ else:
+ p = self.vals.defaults
+ if os.path.exists(p):
+ self.load(p)
+ break
+ else:
+ self.err("Cannot open defaults file %s" % self.vals.defaults)
+
+ def load(self, defaults, help=0):
+ """Load a defaults file. Local variables in the file
+ are used to set options with the same names.
+ Variables are not used to set options that are already specified.
+ """
+ # Create global and lobal dicts for the file.
+ # Initialize locals to the vars.
+ # Use exec to do the standard imports and
+ # define variables we are passing to the script.
+ globals = {}
+ locals = {}
+ locals.update(self.vars)
+ cmd = '\n'.join(["import sys",
+ "import os",
+ "import os.path",
+ "import xen.util.ip",
+ "xm_file = '%s'" % defaults,
+ "xm_help = %d" % help ])
+ exec cmd in globals, locals
+ execfile(defaults, globals, locals)
+ if help: return
+ # Extract the values set by the script and set the corresponding
+ # options, if not set on the command line.
+ vtypes = [ types.StringType,
+ types.ListType,
+ types.IntType,
+ types.FloatType
+ ]
+ for (k, v) in locals.items():
+ if self.specified(k): continue
+ if not(type(v) in vtypes): continue
+ self.setopt(k, v)
+
+def set_true(opt, k, v):
+ """Set an option true."""
+ opt.set(1)
+
+def set_false(opt, k, v):
+ """Set an option false."""
+ opt.set(0)
+
+def set_value(opt, k, v):
+ """Set an option to a valoue."""
+ opt.set(v)
+
+def set_int(opt, k, v):
+ """Set an option to an integer value."""
+ try:
+ v = int(v)
+ except:
+ opt.opts.err('Invalid value: ' + str(v))
+ opt.set(v)
+
+def append_value(opt, k, v):
+ """Append a value to a list option."""
+ opt.append(v)
+
+def set_var(opt, k, v):
+ """Set a default script variable.
+ """
+ (var, val) = v.strip().split('=')
+ opt.opts.setvar(var.strip(), val.strip())
+
--- /dev/null
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+"""Domain shutdown.
+"""
+import string
+import sys
+import time
+
+from xen.xend.XendClient import server
+from xen.xm.opts import *
+
+gopts = Opts(use="""[options] [DOM]
+
+Shutdown one or more domains gracefully.""")
+
+gopts.opt('help', short='h',
+ fn=set_true, default=0,
+ use="Print this help.")
+
+gopts.opt('all', short='a',
+ fn=set_true, default=0,
+ use="Shutdown all domains.")
+
+gopts.opt('wait', short='w',
+ fn=set_true, default=0,
+ use='Wait for shutdown to complete.')
+
+gopts.opt('norestart', short='n',
+ fn=set_true, default=0,
+ use='Prevent domain restart.')
+
+def shutdown(opts, doms, wait):
+ def domains():
+ return [ int(a) for a in server.xend_domains() ]
+ if doms == None: doms = domains()
+ if 0 in doms:
+ doms.remove(0)
+ for d in doms:
+ server.xend_domain_shutdown(d)
+ if wait:
+ while doms:
+ alive = domains()
+ dead = []
+ for d in doms:
+ if d in alive: continue
+ dead.append(d)
+ for d in dead:
+ opts.info("Domain %d terminated" % d)
+ doms.remove(d)
+ time.sleep(1)
+ opts.info("All domains terminated")
+
+def main_all(opts, args):
+ shutdown(opts, None, opts.vals.wait)
+
+def main_dom(opts, args):
+ if len(args) < 1: opts.err('Missing domain')
+ dom = args[0]
+ try:
+ domid = int(dom)
+ except:
+ opts.err('Invalid domain: ' + dom)
+ shutdown(opts, [ domid ], opts.vals.wait)
+
+def main(argv):
+ opts = gopts
+ args = opts.parse(argv)
+ if opts.vals.help:
+ opts.usage()
+ return
+ print 'shutdown.main>', len(args), args
+ if opts.vals.all:
+ main_all(opts, args)
+ else:
+ main_dom(opts, args)
+
+++ /dev/null
-
-all:
- $(MAKE) -C lib
- $(MAKE) -C py
-
-install: all
- $(MAKE) -C lib install
- $(MAKE) -C py install
-
-clean:
- $(MAKE) -C lib clean
- $(MAKE) -C py clean
+++ /dev/null
-
-MAJOR = 1.3
-MINOR = 0
-SONAME = libxc.so.$(MAJOR)
-
-CC = gcc
-
-XEN_ROOT = ../../..
-
-vpath %.h $(XEN_ROOT)/xen/include/hypervisor-ifs
-INCLUDES += -I $(XEN_ROOT)/xen/include/hypervisor-ifs
-
-vpath %.h $(XEN_ROOT)/tools/xu/lib
-INCLUDES += -I $(XEN_ROOT)/tools/xu/lib
-
-vpath %h $(XEN_ROOT)/linux-xen-sparse/include
-INCLUDES += -I $(XEN_ROOT)/linux-xen-sparse/include
-
-vpath %c $(XEN_ROOT)/tools/lib
-INCLUDES += -I $(XEN_ROOT)/tools/lib
-
-LIB_SRCS :=
-LIB_SRCS += allocate.c
-#LIB_SRCS += enum.c
-LIB_SRCS += file_stream.c
-LIB_SRCS += gzip_stream.c
-#LIB_SRCS += hash_table.c
-LIB_SRCS += iostream.c
-#LIB_SRCS += kernel_stream.c
-#LIB_SRCS += lexis.c
-#LIB_SRCS += lzi_stream.c
-#LIB_SRCS += lzo_stream.c
-#LIB_SRCS += marshal.c
-#LIB_SRCS += socket_stream.c
-#LIB_SRCS += string_stream.c
-#LIB_SRCS += sxpr.c
-#LIB_SRCS += sxpr_parser.c
-LIB_SRCS += sys_net.c
-LIB_SRCS += sys_string.c
-#LIB_SRCS += xdr.c
-
-SRCS :=
-SRCS += xc_atropos.c
-SRCS += xc_bvtsched.c
-SRCS += xc_domain.c
-SRCS += xc_evtchn.c
-SRCS += xc_io.c
-SRCS += xc_linux_build.c
-SRCS += xc_linux_restore.c
-SRCS += xc_linux_save.c
-SRCS += xc_misc.c
-SRCS += xc_netbsd_build.c
-SRCS += xc_physdev.c
-SRCS += xc_private.c
-SRCS += xc_rrobin.c
-
-SRCS += $(LIB_SRCS)
-
-#CFLAGS += -I../../../xen/include/hypervisor-ifs
-#CFLAGS += -I../../xu/lib
-#CFLAGS += -I../../../linux-xen-sparse/include
-
-CFLAGS += -Wall
-CFLAGS += -Werror
-CFLAGS += -g
-CFLAGS += -O3
-CFLAGS += -fno-strict-aliasing
-CFLAGS += $(INCLUDES)
-# Get gcc to generate the dependencies for us.
-CFLAGS += -Wp,-MD,.$(@F).d
-DEPS = .*.d
-
-OBJS = $(patsubst %.c,%.o,$(SRCS))
-
-LIB = libxc.so libxc.so.$(MAJOR) libxc.so.$(MAJOR).$(MINOR)
-
-all: check-for-zlib $(LIB)
-
-check-for-zlib:
- @if [ ! -e /usr/include/zlib.h ]; then \
- echo "***********************************************************"; \
- echo "ERROR: install zlib header files (http://www.gzip.org/zlib)"; \
- echo "***********************************************************"; \
- false; \
- fi
-
-install: all
- mkdir -p $(prefix)/usr/lib
- mkdir -p $(prefix)/usr/include
- install -m0755 $(LIB) $(prefix)/usr/lib
- install -m0644 xc.h $(prefix)/usr/include
-
-clean:
- $(RM) *.a *.so *.o *.rpm $(LIB)
- $(RM) *~
- $(RM) $(DEPS)
-
-rpm: all
- rm -rf staging
- mkdir staging
- mkdir staging/i386
- rpmbuild --define "staging$$PWD/staging" --define '_builddir.' \
- --define "_rpmdir$$PWD/staging" -bb rpm.spec
- mv staging/i386/*.rpm .
- rm -rf staging
-
-libxc.so:
- ln -sf libxc.so.$(MAJOR) $@
-libxc.so.$(MAJOR):
- ln -sf libxc.so.$(MAJOR).$(MINOR) $@
-libxc.so.$(MAJOR).$(MINOR): $(OBJS)
- $(CC) -Wl,-soname -Wl,$(SONAME) -shared -o $@ $^ -lz
-
-%.o: %.c Makefile
-
-# $(CC) $(CFLAGS) -o $@ $<
-
--include $(DEPS)
+++ /dev/null
-Summary: Xen control interface library
-Name: xen-internal-library
-Version: 1.2
-Release: 1
-License: Xen
-Group: Xen
-BuildRoot: %{staging}
-%description
-Library to make it easier to access the Xen control interfaces.
-
-%pre
-%preun
-%install
-install -m 0755 -d $RPM_BUILD_ROOT/lib
-install -m 0755 libxc.a $RPM_BUILD_ROOT/lib/libxc.a
-install -m 0755 libxc.so $RPM_BUILD_ROOT/lib/libxc.so
-install -m 0755 -d $RPM_BUILD_ROOT/include
-install -m 0644 xc.h $RPM_BUILD_ROOT/include/xc.h
-%clean
-%post
-%postun
-%files
-%defattr(-,root,root)
-%dir /lib
-/lib/libxc.a
-/lib/libxc.so
-%dir /include
-/include/xc.h
+++ /dev/null
-/******************************************************************************
- * xc.h
- *
- * A library for low-level access to the Xen control interfaces.
- *
- * Copyright (c) 2003, K A Fraser.
- */
-
-#ifndef __XC_H__
-#define __XC_H__
-
-typedef unsigned char u8;
-typedef unsigned short u16;
-typedef unsigned long u32;
-typedef unsigned long long u64;
-typedef signed char s8;
-typedef signed short s16;
-typedef signed long s32;
-typedef signed long long s64;
-
-/* Obtain or relinquish a handle on the 'xc' library. */
-int xc_interface_open(void);
-int xc_interface_close(int xc_handle);
-
-typedef struct {
- u32 domid;
- unsigned int cpu;
- unsigned int dying:1, crashed:1, shutdown:1,
- paused:1, blocked:1, running:1;
- unsigned int shutdown_reason; /* only meaningful if shutdown==1 */
- unsigned long nr_pages;
- unsigned long shared_info_frame;
- u64 cpu_time;
-#define XC_DOMINFO_MAXNAME 16
- char name[XC_DOMINFO_MAXNAME];
- unsigned long max_memkb;
-} xc_dominfo_t;
-
-typedef struct xc_shadow_control_stats_st
-{
- unsigned long fault_count;
- unsigned long dirty_count;
- unsigned long dirty_net_count;
- unsigned long dirty_block_count;
-} xc_shadow_control_stats_t;
-
-int xc_domain_create(int xc_handle,
- unsigned int mem_kb,
- const char *name,
- int cpu,
- u32 *pdomid);
-int xc_domain_pause(int xc_handle,
- u32 domid);
-int xc_domain_unpause(int xc_handle,
- u32 domid);
-int xc_domain_destroy(int xc_handle,
- u32 domid);
-int xc_domain_pincpu(int xc_handle,
- u32 domid,
- int cpu);
-int xc_domain_getinfo(int xc_handle,
- u32 first_domid,
- unsigned int max_doms,
- xc_dominfo_t *info);
-
-int xc_shadow_control(int xc_handle,
- u32 domid,
- unsigned int sop,
- unsigned long *dirty_bitmap,
- unsigned long pages,
- xc_shadow_control_stats_t *stats);
-
-
-#define XCFLAGS_VERBOSE 1
-#define XCFLAGS_LIVE 2
-#define XCFLAGS_DEBUG 4
-
-struct XcIOContext;
-int xc_linux_save(int xc_handle, struct XcIOContext *ioctxt);
-int xc_linux_restore(int xc_handle, struct XcIOContext *ioctxt);
-
-int xc_linux_build(int xc_handle,
- u32 domid,
- const char *image_name,
- const char *ramdisk_name,
- const char *cmdline,
- unsigned int control_evtchn,
- unsigned long flags);
-
-int xc_netbsd_build(int xc_handle,
- u32 domid,
- const char *image_name,
- const char *cmdline,
- unsigned int control_evtchn);
-
-int xc_bvtsched_global_set(int xc_handle,
- unsigned long ctx_allow);
-
-int xc_bvtsched_domain_set(int xc_handle,
- u32 domid,
- unsigned long mcuadv,
- unsigned long warp,
- unsigned long warpl,
- unsigned long warpu);
-
-int xc_bvtsched_global_get(int xc_handle,
- unsigned long *ctx_allow);
-
-int xc_bvtsched_domain_get(int xc_handle,
- u32 domid,
- unsigned long *mcuadv,
- unsigned long *warp,
- unsigned long *warpl,
- unsigned long *warpu);
-
-int xc_atropos_domain_set(int xc_handle,
- u32 domid,
- u64 period, u64 slice, u64 latency,
- int xtratime);
-
-int xc_atropos_domain_get(int xc_handle,
- u32 domid,
- u64* period, u64 *slice, u64 *latency,
- int *xtratime);
-
-int xc_rrobin_global_set(int xc_handle, u64 slice);
-
-int xc_rrobin_global_get(int xc_handle, u64 *slice);
-
-#define DOMID_SELF (0x7FFFFFFEU)
-
-typedef struct {
-#define EVTCHNSTAT_closed 0 /* Chennel is not in use. */
-#define EVTCHNSTAT_unbound 1 /* Channel is not bound to a source. */
-#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */
-#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */
-#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */
- int status;
- union {
- struct {
- u32 dom;
- int port;
- } interdomain;
- int pirq;
- int virq;
- } u;
-} xc_evtchn_status_t;
-
-int xc_evtchn_bind_interdomain(int xc_handle,
- u32 dom1, /* may be DOMID_SELF */
- u32 dom2, /* may be DOMID_SELF */
- int *port1,
- int *port2);
-int xc_evtchn_bind_virq(int xc_handle,
- int virq,
- int *port);
-int xc_evtchn_close(int xc_handle,
- u32 dom, /* may be DOMID_SELF */
- int port);
-int xc_evtchn_send(int xc_handle,
- int local_port);
-int xc_evtchn_status(int xc_handle,
- u32 dom, /* may be DOMID_SELF */
- int port,
- xc_evtchn_status_t *status);
-
-int xc_physdev_pci_access_modify(int xc_handle,
- u32 domid,
- int bus,
- int dev,
- int func,
- int enable);
-
-int xc_readconsolering(int xc_handle,
- char *str,
- unsigned int max_chars,
- int clear);
-
-typedef struct {
- int ht_per_core;
- int cores;
- unsigned long total_pages;
- unsigned long free_pages;
- unsigned long cpu_khz;
-} xc_physinfo_t;
-
-int xc_physinfo(int xc_handle,
- xc_physinfo_t *info);
-
-int xc_domain_setname(int xc_handle,
- u32 domid,
- char *name);
-
-int xc_domain_setinitialmem(int xc_handle,
- u32 domid,
- unsigned int initial_memkb);
-
-int xc_domain_setmaxmem(int xc_handle,
- u32 domid,
- unsigned int max_memkb);
-
-
-#endif /* __XC_H__ */
+++ /dev/null
-/******************************************************************************
- * xc_atropos.c
- *
- * API for manipulating parameters of the Atropos scheduler.
- *
- * by Mark Williamson, Copyright (c) 2004 Intel Research Cambridge.
- */
-
-#include "xc_private.h"
-
-int xc_atropos_domain_set(int xc_handle,
- u32 domid, u64 period, u64 slice, u64 latency,
- int xtratime)
-{
- dom0_op_t op;
- struct atropos_adjdom *p = &op.u.adjustdom.u.atropos;
-
- op.cmd = DOM0_ADJUSTDOM;
- op.u.adjustdom.domain = (domid_t)domid;
- op.u.adjustdom.sched_id = SCHED_ATROPOS;
- op.u.adjustdom.direction = SCHED_INFO_PUT;
-
- p->nat_period = period;
- p->nat_slice = slice;
- p->latency = latency;
- p->xtratime = xtratime;
-
- return do_dom0_op(xc_handle, &op);
-}
-
-int xc_atropos_domain_get(int xc_handle, u32 domid, u64 *period,
- u64 *slice, u64 *latency, int *xtratime)
-{
- dom0_op_t op;
- int ret;
- struct atropos_adjdom *p = &op.u.adjustdom.u.atropos;
-
- op.cmd = DOM0_ADJUSTDOM;
- op.u.adjustdom.domain = (domid_t)domid;
- op.u.adjustdom.sched_id = SCHED_ATROPOS;
- op.u.adjustdom.direction = SCHED_INFO_GET;
-
- ret = do_dom0_op(xc_handle, &op);
-
- *period = p->nat_period;
- *slice = p->nat_slice;
- *latency = p->latency;
- *xtratime = p->xtratime;
-
- return ret;
-}
+++ /dev/null
-/******************************************************************************
- * xc_bvtsched.c
- *
- * API for manipulating parameters of the Borrowed Virtual Time scheduler.
- *
- * Copyright (c) 2003, K A Fraser.
- */
-
-#include "xc_private.h"
-
-int xc_bvtsched_global_set(int xc_handle,
- unsigned long ctx_allow)
-{
- dom0_op_t op;
-
- op.cmd = DOM0_SCHEDCTL;
- op.u.schedctl.sched_id = SCHED_BVT;
- op.u.schedctl.direction = SCHED_INFO_PUT;
- op.u.schedctl.u.bvt.ctx_allow = ctx_allow;
-
- return do_dom0_op(xc_handle, &op);
-}
-
-int xc_bvtsched_global_get(int xc_handle,
- unsigned long *ctx_allow)
-{
- dom0_op_t op;
- int ret;
-
- op.cmd = DOM0_SCHEDCTL;
- op.u.schedctl.sched_id = SCHED_BVT;
- op.u.schedctl.direction = SCHED_INFO_GET;
-
- ret = do_dom0_op(xc_handle, &op);
-
- *ctx_allow = op.u.schedctl.u.bvt.ctx_allow;
-
- return ret;
-}
-
-int xc_bvtsched_domain_set(int xc_handle,
- u32 domid,
- unsigned long mcuadv,
- unsigned long warp,
- unsigned long warpl,
- unsigned long warpu)
-{
- dom0_op_t op;
- struct bvt_adjdom *bvtadj = &op.u.adjustdom.u.bvt;
-
- op.cmd = DOM0_ADJUSTDOM;
- op.u.adjustdom.domain = (domid_t)domid;
- op.u.adjustdom.sched_id = SCHED_BVT;
- op.u.adjustdom.direction = SCHED_INFO_PUT;
-
- bvtadj->mcu_adv = mcuadv;
- bvtadj->warp = warp;
- bvtadj->warpl = warpl;
- bvtadj->warpu = warpu;
- return do_dom0_op(xc_handle, &op);
-}
-
-
-int xc_bvtsched_domain_get(int xc_handle,
- u32 domid,
- unsigned long *mcuadv,
- unsigned long *warp,
- unsigned long *warpl,
- unsigned long *warpu)
-{
-
- dom0_op_t op;
- int ret;
- struct bvt_adjdom *adjptr = &op.u.adjustdom.u.bvt;
-
- op.cmd = DOM0_ADJUSTDOM;
- op.u.adjustdom.domain = (domid_t)domid;
- op.u.adjustdom.sched_id = SCHED_BVT;
- op.u.adjustdom.direction = SCHED_INFO_GET;
-
- ret = do_dom0_op(xc_handle, &op);
-
- *mcuadv = adjptr->mcu_adv;
- *warp = adjptr->warp;
- *warpl = adjptr->warpl;
- *warpu = adjptr->warpu;
- return ret;
-}
+++ /dev/null
-/******************************************************************************
- * xc_domain.c
- *
- * API for manipulating and obtaining information on domains.
- *
- * Copyright (c) 2003, K A Fraser.
- */
-
-#include "xc_private.h"
-
-int xc_domain_create(int xc_handle,
- unsigned int mem_kb,
- const char *name,
- int cpu,
- u32 *pdomid)
-{
- int err;
- dom0_op_t op;
-
- op.cmd = DOM0_CREATEDOMAIN;
- op.u.createdomain.memory_kb = mem_kb;
- strncpy(op.u.createdomain.name, name, MAX_DOMAIN_NAME);
- op.u.createdomain.name[MAX_DOMAIN_NAME-1] = '\0';
- op.u.createdomain.cpu = cpu;
-
- if ( (err = do_dom0_op(xc_handle, &op)) == 0 )
- *pdomid = (u32)op.u.createdomain.domain;
-
- return err;
-}
-
-
-int xc_domain_pause(int xc_handle,
- u32 domid)
-{
- dom0_op_t op;
- op.cmd = DOM0_PAUSEDOMAIN;
- op.u.pausedomain.domain = (domid_t)domid;
- return do_dom0_op(xc_handle, &op);
-}
-
-
-int xc_domain_unpause(int xc_handle,
- u32 domid)
-{
- dom0_op_t op;
- op.cmd = DOM0_UNPAUSEDOMAIN;
- op.u.unpausedomain.domain = (domid_t)domid;
- return do_dom0_op(xc_handle, &op);
-}
-
-
-int xc_domain_destroy(int xc_handle,
- u32 domid)
-{
- dom0_op_t op;
- op.cmd = DOM0_DESTROYDOMAIN;
- op.u.destroydomain.domain = (domid_t)domid;
- return do_dom0_op(xc_handle, &op);
-}
-
-int xc_domain_pincpu(int xc_handle,
- u32 domid,
- int cpu)
-{
- dom0_op_t op;
- op.cmd = DOM0_PINCPUDOMAIN;
- op.u.pincpudomain.domain = (domid_t)domid;
- op.u.pincpudomain.cpu = cpu;
- return do_dom0_op(xc_handle, &op);
-}
-
-
-int xc_domain_getinfo(int xc_handle,
- u32 first_domid,
- unsigned int max_doms,
- xc_dominfo_t *info)
-{
- unsigned int nr_doms;
- u32 next_domid = first_domid;
- dom0_op_t op;
-
- for ( nr_doms = 0; nr_doms < max_doms; nr_doms++ )
- {
- op.cmd = DOM0_GETDOMAININFO;
- op.u.getdomaininfo.domain = (domid_t)next_domid;
- op.u.getdomaininfo.ctxt = NULL; /* no exec context info, thanks. */
- if ( do_dom0_op(xc_handle, &op) < 0 )
- break;
- info->domid = (u32)op.u.getdomaininfo.domain;
-
- info->cpu =
- (op.u.getdomaininfo.flags>>DOMFLAGS_CPUSHIFT) & DOMFLAGS_CPUMASK;
-
- info->dying = !!(op.u.getdomaininfo.flags & DOMFLAGS_DYING);
- info->crashed = !!(op.u.getdomaininfo.flags & DOMFLAGS_CRASHED);
- info->shutdown = !!(op.u.getdomaininfo.flags & DOMFLAGS_SHUTDOWN);
- info->paused = !!(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED);
- info->blocked = !!(op.u.getdomaininfo.flags & DOMFLAGS_BLOCKED);
- info->running = !!(op.u.getdomaininfo.flags & DOMFLAGS_RUNNING);
-
- info->shutdown_reason =
- (op.u.getdomaininfo.flags>>DOMFLAGS_SHUTDOWNSHIFT) &
- DOMFLAGS_SHUTDOWNMASK;
-
- info->nr_pages = op.u.getdomaininfo.tot_pages;
- info->max_memkb = op.u.getdomaininfo.max_pages<<(PAGE_SHIFT-10);
- info->shared_info_frame = op.u.getdomaininfo.shared_info_frame;
- info->cpu_time = op.u.getdomaininfo.cpu_time;
- strncpy(info->name, op.u.getdomaininfo.name, XC_DOMINFO_MAXNAME);
- info->name[XC_DOMINFO_MAXNAME-1] = '\0';
-
- next_domid = (u32)op.u.getdomaininfo.domain + 1;
- info++;
- }
-
- return nr_doms;
-}
-
-int xc_domain_getfullinfo(int xc_handle,
- u32 domid,
- dom0_op_t *op,
- full_execution_context_t *ctxt )
-{
- int rc;
- op->cmd = DOM0_GETDOMAININFO;
- op->u.getdomaininfo.domain = (domid_t)domid;
- op->u.getdomaininfo.ctxt = ctxt;
-
- rc = do_dom0_op(xc_handle, op);
- if ( ((u32)op->u.getdomaininfo.domain != domid) && rc > 0 )
- return -ESRCH;
- else
- return rc;
-}
-
-
-int xc_shadow_control(int xc_handle,
- u32 domid,
- unsigned int sop,
- unsigned long *dirty_bitmap,
- unsigned long pages,
- xc_shadow_control_stats_t *stats )
-{
- int rc;
- dom0_op_t op;
- op.cmd = DOM0_SHADOW_CONTROL;
- op.u.shadow_control.domain = (domid_t)domid;
- op.u.shadow_control.op = sop;
- op.u.shadow_control.dirty_bitmap = dirty_bitmap;
- op.u.shadow_control.pages = pages;
-
- rc = do_dom0_op(xc_handle, &op);
-
- if ( stats )
- memcpy(stats, &op.u.shadow_control.stats,
- sizeof(xc_shadow_control_stats_t));
-
- return (rc == 0) ? op.u.shadow_control.pages : rc;
-}
-
-int xc_domain_setname(int xc_handle,
- u32 domid,
- char *name)
-{
- dom0_op_t op;
- op.cmd = DOM0_SETDOMAINNAME;
- op.u.setdomainname.domain = (domid_t)domid;
- strncpy(op.u.setdomainname.name, name, MAX_DOMAIN_NAME);
- return do_dom0_op(xc_handle, &op);
-}
-
-int xc_domain_setinitialmem(int xc_handle,
- u32 domid,
- unsigned int initial_memkb)
-{
- dom0_op_t op;
- op.cmd = DOM0_SETDOMAININITIALMEM;
- op.u.setdomaininitialmem.domain = (domid_t)domid;
- op.u.setdomaininitialmem.initial_memkb = initial_memkb;
- return do_dom0_op(xc_handle, &op);
-}
-
-int xc_domain_setmaxmem(int xc_handle,
- u32 domid,
- unsigned int max_memkb)
-{
- dom0_op_t op;
- op.cmd = DOM0_SETDOMAINMAXMEM;
- op.u.setdomainmaxmem.domain = (domid_t)domid;
- op.u.setdomainmaxmem.max_memkb = max_memkb;
- return do_dom0_op(xc_handle, &op);
-}
-
+++ /dev/null
-/*
- * Copyright (c) 1995, 1996 Erik Theisen. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-typedef u_int8_t Elf_Byte;
-
-typedef u_int32_t Elf32_Addr; /* Unsigned program address */
-typedef u_int32_t Elf32_Off; /* Unsigned file offset */
-typedef int32_t Elf32_Sword; /* Signed large integer */
-typedef u_int32_t Elf32_Word; /* Unsigned large integer */
-typedef u_int16_t Elf32_Half; /* Unsigned medium integer */
-
-typedef u_int64_t Elf64_Addr;
-typedef u_int64_t Elf64_Off;
-typedef int32_t Elf64_Shalf;
-
-typedef int32_t Elf64_Sword;
-typedef u_int32_t Elf64_Word;
-
-typedef int64_t Elf64_Sxword;
-typedef u_int64_t Elf64_Xword;
-
-typedef u_int32_t Elf64_Half;
-typedef u_int16_t Elf64_Quarter;
-
-/*
- * e_ident[] identification indexes
- * See http://www.caldera.com/developers/gabi/2000-07-17/ch4.eheader.html
- */
-#define EI_MAG0 0 /* file ID */
-#define EI_MAG1 1 /* file ID */
-#define EI_MAG2 2 /* file ID */
-#define EI_MAG3 3 /* file ID */
-#define EI_CLASS 4 /* file class */
-#define EI_DATA 5 /* data encoding */
-#define EI_VERSION 6 /* ELF header version */
-#define EI_OSABI 7 /* OS/ABI ID */
-#define EI_ABIVERSION 8 /* ABI version */
-#define EI_PAD 9 /* start of pad bytes */
-#define EI_NIDENT 16 /* Size of e_ident[] */
-
-/* e_ident[] magic number */
-#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */
-#define ELFMAG1 'E' /* e_ident[EI_MAG1] */
-#define ELFMAG2 'L' /* e_ident[EI_MAG2] */
-#define ELFMAG3 'F' /* e_ident[EI_MAG3] */
-#define ELFMAG "\177ELF" /* magic */
-#define SELFMAG 4 /* size of magic */
-
-/* e_ident[] file class */
-#define ELFCLASSNONE 0 /* invalid */
-#define ELFCLASS32 1 /* 32-bit objs */
-#define ELFCLASS64 2 /* 64-bit objs */
-#define ELFCLASSNUM 3 /* number of classes */
-
-/* e_ident[] data encoding */
-#define ELFDATANONE 0 /* invalid */
-#define ELFDATA2LSB 1 /* Little-Endian */
-#define ELFDATA2MSB 2 /* Big-Endian */
-#define ELFDATANUM 3 /* number of data encode defines */
-
-/* e_ident[] Operating System/ABI */
-#define ELFOSABI_SYSV 0 /* UNIX System V ABI */
-#define ELFOSABI_HPUX 1 /* HP-UX operating system */
-#define ELFOSABI_NETBSD 2 /* NetBSD */
-#define ELFOSABI_LINUX 3 /* GNU/Linux */
-#define ELFOSABI_HURD 4 /* GNU/Hurd */
-#define ELFOSABI_86OPEN 5 /* 86Open common IA32 ABI */
-#define ELFOSABI_SOLARIS 6 /* Solaris */
-#define ELFOSABI_MONTEREY 7 /* Monterey */
-#define ELFOSABI_IRIX 8 /* IRIX */
-#define ELFOSABI_FREEBSD 9 /* FreeBSD */
-#define ELFOSABI_TRU64 10 /* TRU64 UNIX */
-#define ELFOSABI_MODESTO 11 /* Novell Modesto */
-#define ELFOSABI_OPENBSD 12 /* OpenBSD */
-#define ELFOSABI_ARM 97 /* ARM */
-#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
-
-/* e_ident */
-#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
- (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
- (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
- (ehdr).e_ident[EI_MAG3] == ELFMAG3)
-
-/* ELF Header */
-typedef struct elfhdr {
- unsigned char e_ident[EI_NIDENT]; /* ELF Identification */
- Elf32_Half e_type; /* object file type */
- Elf32_Half e_machine; /* machine */
- Elf32_Word e_version; /* object file version */
- Elf32_Addr e_entry; /* virtual entry point */
- Elf32_Off e_phoff; /* program header table offset */
- Elf32_Off e_shoff; /* section header table offset */
- Elf32_Word e_flags; /* processor-specific flags */
- Elf32_Half e_ehsize; /* ELF header size */
- Elf32_Half e_phentsize; /* program header entry size */
- Elf32_Half e_phnum; /* number of program header entries */
- Elf32_Half e_shentsize; /* section header entry size */
- Elf32_Half e_shnum; /* number of section header entries */
- Elf32_Half e_shstrndx; /* section header table's "section
- header string table" entry offset */
-} Elf32_Ehdr;
-
-typedef struct {
- unsigned char e_ident[EI_NIDENT]; /* Id bytes */
- Elf64_Quarter e_type; /* file type */
- Elf64_Quarter e_machine; /* machine type */
- Elf64_Half e_version; /* version number */
- Elf64_Addr e_entry; /* entry point */
- Elf64_Off e_phoff; /* Program hdr offset */
- Elf64_Off e_shoff; /* Section hdr offset */
- Elf64_Half e_flags; /* Processor flags */
- Elf64_Quarter e_ehsize; /* sizeof ehdr */
- Elf64_Quarter e_phentsize; /* Program header entry size */
- Elf64_Quarter e_phnum; /* Number of program headers */
- Elf64_Quarter e_shentsize; /* Section header entry size */
- Elf64_Quarter e_shnum; /* Number of section headers */
- Elf64_Quarter e_shstrndx; /* String table index */
-} Elf64_Ehdr;
-
-/* e_type */
-#define ET_NONE 0 /* No file type */
-#define ET_REL 1 /* relocatable file */
-#define ET_EXEC 2 /* executable file */
-#define ET_DYN 3 /* shared object file */
-#define ET_CORE 4 /* core file */
-#define ET_NUM 5 /* number of types */
-#define ET_LOPROC 0xff00 /* reserved range for processor */
-#define ET_HIPROC 0xffff /* specific e_type */
-
-/* e_machine */
-#define EM_NONE 0 /* No Machine */
-#define EM_M32 1 /* AT&T WE 32100 */
-#define EM_SPARC 2 /* SPARC */
-#define EM_386 3 /* Intel 80386 */
-#define EM_68K 4 /* Motorola 68000 */
-#define EM_88K 5 /* Motorola 88000 */
-#define EM_486 6 /* Intel 80486 - unused? */
-#define EM_860 7 /* Intel 80860 */
-#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */
-/*
- * Don't know if EM_MIPS_RS4_BE,
- * EM_SPARC64, EM_PARISC,
- * or EM_PPC are ABI compliant
- */
-#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */
-#define EM_SPARC64 11 /* SPARC v9 64-bit unoffical */
-#define EM_PARISC 15 /* HPPA */
-#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */
-#define EM_PPC 20 /* PowerPC */
-#define EM_ARM 40 /* Advanced RISC Machines ARM */
-#define EM_ALPHA 41 /* DEC ALPHA */
-#define EM_SPARCV9 43 /* SPARC version 9 */
-#define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */
-#define EM_X86_64 62 /* AMD x86-64 architecture */
-#define EM_VAX 75 /* DEC VAX */
-#define EM_NUM 15 /* number of machine types */
-
-/* Version */
-#define EV_NONE 0 /* Invalid */
-#define EV_CURRENT 1 /* Current */
-#define EV_NUM 2 /* number of versions */
-
-/* Section Header */
-typedef struct {
- Elf32_Word sh_name; /* name - index into section header
- string table section */
- Elf32_Word sh_type; /* type */
- Elf32_Word sh_flags; /* flags */
- Elf32_Addr sh_addr; /* address */
- Elf32_Off sh_offset; /* file offset */
- Elf32_Word sh_size; /* section size */
- Elf32_Word sh_link; /* section header table index link */
- Elf32_Word sh_info; /* extra information */
- Elf32_Word sh_addralign; /* address alignment */
- Elf32_Word sh_entsize; /* section entry size */
-} Elf32_Shdr;
-
-typedef struct {
- Elf64_Half sh_name; /* section name */
- Elf64_Half sh_type; /* section type */
- Elf64_Xword sh_flags; /* section flags */
- Elf64_Addr sh_addr; /* virtual address */
- Elf64_Off sh_offset; /* file offset */
- Elf64_Xword sh_size; /* section size */
- Elf64_Half sh_link; /* link to another */
- Elf64_Half sh_info; /* misc info */
- Elf64_Xword sh_addralign; /* memory alignment */
- Elf64_Xword sh_entsize; /* table entry size */
-} Elf64_Shdr;
-
-/* Special Section Indexes */
-#define SHN_UNDEF 0 /* undefined */
-#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */
-#define SHN_LOPROC 0xff00 /* reserved range for processor */
-#define SHN_HIPROC 0xff1f /* specific section indexes */
-#define SHN_ABS 0xfff1 /* absolute value */
-#define SHN_COMMON 0xfff2 /* common symbol */
-#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */
-
-/* sh_type */
-#define SHT_NULL 0 /* inactive */
-#define SHT_PROGBITS 1 /* program defined information */
-#define SHT_SYMTAB 2 /* symbol table section */
-#define SHT_STRTAB 3 /* string table section */
-#define SHT_RELA 4 /* relocation section with addends*/
-#define SHT_HASH 5 /* symbol hash table section */
-#define SHT_DYNAMIC 6 /* dynamic section */
-#define SHT_NOTE 7 /* note section */
-#define SHT_NOBITS 8 /* no space section */
-#define SHT_REL 9 /* relation section without addends */
-#define SHT_SHLIB 10 /* reserved - purpose unknown */
-#define SHT_DYNSYM 11 /* dynamic symbol table section */
-#define SHT_NUM 12 /* number of section types */
-#define SHT_LOPROC 0x70000000 /* reserved range for processor */
-#define SHT_HIPROC 0x7fffffff /* specific section header types */
-#define SHT_LOUSER 0x80000000 /* reserved range for application */
-#define SHT_HIUSER 0xffffffff /* specific indexes */
-
-/* Section names */
-#define ELF_BSS ".bss" /* uninitialized data */
-#define ELF_DATA ".data" /* initialized data */
-#define ELF_DEBUG ".debug" /* debug */
-#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */
-#define ELF_DYNSTR ".dynstr" /* dynamic string table */
-#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */
-#define ELF_FINI ".fini" /* termination code */
-#define ELF_GOT ".got" /* global offset table */
-#define ELF_HASH ".hash" /* symbol hash table */
-#define ELF_INIT ".init" /* initialization code */
-#define ELF_REL_DATA ".rel.data" /* relocation data */
-#define ELF_REL_FINI ".rel.fini" /* relocation termination code */
-#define ELF_REL_INIT ".rel.init" /* relocation initialization code */
-#define ELF_REL_DYN ".rel.dyn" /* relocaltion dynamic link info */
-#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */
-#define ELF_REL_TEXT ".rel.text" /* relocation code */
-#define ELF_RODATA ".rodata" /* read-only data */
-#define ELF_SHSTRTAB ".shstrtab" /* section header string table */
-#define ELF_STRTAB ".strtab" /* string table */
-#define ELF_SYMTAB ".symtab" /* symbol table */
-#define ELF_TEXT ".text" /* code */
-
-
-/* Section Attribute Flags - sh_flags */
-#define SHF_WRITE 0x1 /* Writable */
-#define SHF_ALLOC 0x2 /* occupies memory */
-#define SHF_EXECINSTR 0x4 /* executable */
-#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor */
- /* specific section attributes */
-
-/* Symbol Table Entry */
-typedef struct elf32_sym {
- Elf32_Word st_name; /* name - index into string table */
- Elf32_Addr st_value; /* symbol value */
- Elf32_Word st_size; /* symbol size */
- unsigned char st_info; /* type and binding */
- unsigned char st_other; /* 0 - no defined meaning */
- Elf32_Half st_shndx; /* section header index */
-} Elf32_Sym;
-
-typedef struct {
- Elf64_Half st_name; /* Symbol name index in str table */
- Elf_Byte st_info; /* type / binding attrs */
- Elf_Byte st_other; /* unused */
- Elf64_Quarter st_shndx; /* section index of symbol */
- Elf64_Xword st_value; /* value of symbol */
- Elf64_Xword st_size; /* size of symbol */
-} Elf64_Sym;
-
-/* Symbol table index */
-#define STN_UNDEF 0 /* undefined */
-
-/* Extract symbol info - st_info */
-#define ELF32_ST_BIND(x) ((x) >> 4)
-#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf)
-#define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf))
-
-#define ELF64_ST_BIND(x) ((x) >> 4)
-#define ELF64_ST_TYPE(x) (((unsigned int) x) & 0xf)
-#define ELF64_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf))
-
-/* Symbol Binding - ELF32_ST_BIND - st_info */
-#define STB_LOCAL 0 /* Local symbol */
-#define STB_GLOBAL 1 /* Global symbol */
-#define STB_WEAK 2 /* like global - lower precedence */
-#define STB_NUM 3 /* number of symbol bindings */
-#define STB_LOPROC 13 /* reserved range for processor */
-#define STB_HIPROC 15 /* specific symbol bindings */
-
-/* Symbol type - ELF32_ST_TYPE - st_info */
-#define STT_NOTYPE 0 /* not specified */
-#define STT_OBJECT 1 /* data object */
-#define STT_FUNC 2 /* function */
-#define STT_SECTION 3 /* section */
-#define STT_FILE 4 /* file */
-#define STT_NUM 5 /* number of symbol types */
-#define STT_LOPROC 13 /* reserved range for processor */
-#define STT_HIPROC 15 /* specific symbol types */
-
-/* Relocation entry with implicit addend */
-typedef struct {
- Elf32_Addr r_offset; /* offset of relocation */
- Elf32_Word r_info; /* symbol table index and type */
-} Elf32_Rel;
-
-/* Relocation entry with explicit addend */
-typedef struct {
- Elf32_Addr r_offset; /* offset of relocation */
- Elf32_Word r_info; /* symbol table index and type */
- Elf32_Sword r_addend;
-} Elf32_Rela;
-
-/* Extract relocation info - r_info */
-#define ELF32_R_SYM(i) ((i) >> 8)
-#define ELF32_R_TYPE(i) ((unsigned char) (i))
-#define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t))
-
-typedef struct {
- Elf64_Xword r_offset; /* where to do it */
- Elf64_Xword r_info; /* index & type of relocation */
-} Elf64_Rel;
-
-typedef struct {
- Elf64_Xword r_offset; /* where to do it */
- Elf64_Xword r_info; /* index & type of relocation */
- Elf64_Sxword r_addend; /* adjustment value */
-} Elf64_Rela;
-
-#define ELF64_R_SYM(info) ((info) >> 32)
-#define ELF64_R_TYPE(info) ((info) & 0xFFFFFFFF)
-#define ELF64_R_INFO(s,t) (((s) << 32) + (u_int32_t)(t))
-
-/* Program Header */
-typedef struct {
- Elf32_Word p_type; /* segment type */
- Elf32_Off p_offset; /* segment offset */
- Elf32_Addr p_vaddr; /* virtual address of segment */
- Elf32_Addr p_paddr; /* physical address - ignored? */
- Elf32_Word p_filesz; /* number of bytes in file for seg. */
- Elf32_Word p_memsz; /* number of bytes in mem. for seg. */
- Elf32_Word p_flags; /* flags */
- Elf32_Word p_align; /* memory alignment */
-} Elf32_Phdr;
-
-typedef struct {
- Elf64_Half p_type; /* entry type */
- Elf64_Half p_flags; /* flags */
- Elf64_Off p_offset; /* offset */
- Elf64_Addr p_vaddr; /* virtual address */
- Elf64_Addr p_paddr; /* physical address */
- Elf64_Xword p_filesz; /* file size */
- Elf64_Xword p_memsz; /* memory size */
- Elf64_Xword p_align; /* memory & file alignment */
-} Elf64_Phdr;
-
-/* Segment types - p_type */
-#define PT_NULL 0 /* unused */
-#define PT_LOAD 1 /* loadable segment */
-#define PT_DYNAMIC 2 /* dynamic linking section */
-#define PT_INTERP 3 /* the RTLD */
-#define PT_NOTE 4 /* auxiliary information */
-#define PT_SHLIB 5 /* reserved - purpose undefined */
-#define PT_PHDR 6 /* program header */
-#define PT_NUM 7 /* Number of segment types */
-#define PT_LOPROC 0x70000000 /* reserved range for processor */
-#define PT_HIPROC 0x7fffffff /* specific segment types */
-
-/* Segment flags - p_flags */
-#define PF_X 0x1 /* Executable */
-#define PF_W 0x2 /* Writable */
-#define PF_R 0x4 /* Readable */
-#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */
- /* specific segment flags */
-
-/* Dynamic structure */
-typedef struct {
- Elf32_Sword d_tag; /* controls meaning of d_val */
- union {
- Elf32_Word d_val; /* Multiple meanings - see d_tag */
- Elf32_Addr d_ptr; /* program virtual address */
- } d_un;
-} Elf32_Dyn;
-
-typedef struct {
- Elf64_Xword d_tag; /* controls meaning of d_val */
- union {
- Elf64_Addr d_ptr;
- Elf64_Xword d_val;
- } d_un;
-} Elf64_Dyn;
-
-/* Dynamic Array Tags - d_tag */
-#define DT_NULL 0 /* marks end of _DYNAMIC array */
-#define DT_NEEDED 1 /* string table offset of needed lib */
-#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */
-#define DT_PLTGOT 3 /* address PLT/GOT */
-#define DT_HASH 4 /* address of symbol hash table */
-#define DT_STRTAB 5 /* address of string table */
-#define DT_SYMTAB 6 /* address of symbol table */
-#define DT_RELA 7 /* address of relocation table */
-#define DT_RELASZ 8 /* size of relocation table */
-#define DT_RELAENT 9 /* size of relocation entry */
-#define DT_STRSZ 10 /* size of string table */
-#define DT_SYMENT 11 /* size of symbol table entry */
-#define DT_INIT 12 /* address of initialization func. */
-#define DT_FINI 13 /* address of termination function */
-#define DT_SONAME 14 /* string table offset of shared obj */
-#define DT_RPATH 15 /* string table offset of library
- search path */
-#define DT_SYMBOLIC 16 /* start sym search in shared obj. */
-#define DT_REL 17 /* address of rel. tbl. w addends */
-#define DT_RELSZ 18 /* size of DT_REL relocation table */
-#define DT_RELENT 19 /* size of DT_REL relocation entry */
-#define DT_PLTREL 20 /* PLT referenced relocation entry */
-#define DT_DEBUG 21 /* bugger */
-#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */
-#define DT_JMPREL 23 /* add. of PLT's relocation entries */
-#define DT_BIND_NOW 24 /* Bind now regardless of env setting */
-#define DT_NUM 25 /* Number used. */
-#define DT_LOPROC 0x70000000 /* reserved range for processor */
-#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */
-
-/* Standard ELF hashing function */
-unsigned int elf_hash(const unsigned char *name);
-
-/*
- * Note Definitions
- */
-typedef struct {
- Elf32_Word namesz;
- Elf32_Word descsz;
- Elf32_Word type;
-} Elf32_Note;
-
-typedef struct {
- Elf64_Half namesz;
- Elf64_Half descsz;
- Elf64_Half type;
-} Elf64_Note;
-
-
-#if defined(ELFSIZE)
-#define CONCAT(x,y) __CONCAT(x,y)
-#define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x)))
-#define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y))))
-#define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE))
-#define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x)))
-#endif
-
-#if defined(ELFSIZE) && (ELFSIZE == 32)
-#define Elf_Ehdr Elf32_Ehdr
-#define Elf_Phdr Elf32_Phdr
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Rel Elf32_Rel
-#define Elf_RelA Elf32_Rela
-#define Elf_Dyn Elf32_Dyn
-#define Elf_Word Elf32_Word
-#define Elf_Sword Elf32_Sword
-#define Elf_Addr Elf32_Addr
-#define Elf_Off Elf32_Off
-#define Elf_Nhdr Elf32_Nhdr
-#define Elf_Note Elf32_Note
-
-#define ELF_R_SYM ELF32_R_SYM
-#define ELF_R_TYPE ELF32_R_TYPE
-#define ELF_R_INFO ELF32_R_INFO
-#define ELFCLASS ELFCLASS32
-
-#define ELF_ST_BIND ELF32_ST_BIND
-#define ELF_ST_TYPE ELF32_ST_TYPE
-#define ELF_ST_INFO ELF32_ST_INFO
-
-#define AuxInfo Aux32Info
-#elif defined(ELFSIZE) && (ELFSIZE == 64)
-#define Elf_Ehdr Elf64_Ehdr
-#define Elf_Phdr Elf64_Phdr
-#define Elf_Shdr Elf64_Shdr
-#define Elf_Sym Elf64_Sym
-#define Elf_Rel Elf64_Rel
-#define Elf_RelA Elf64_Rela
-#define Elf_Dyn Elf64_Dyn
-#define Elf_Word Elf64_Word
-#define Elf_Sword Elf64_Sword
-#define Elf_Addr Elf64_Addr
-#define Elf_Off Elf64_Off
-#define Elf_Nhdr Elf64_Nhdr
-#define Elf_Note Elf64_Note
-
-#define ELF_R_SYM ELF64_R_SYM
-#define ELF_R_TYPE ELF64_R_TYPE
-#define ELF_R_INFO ELF64_R_INFO
-#define ELFCLASS ELFCLASS64
-
-#define ELF_ST_BIND ELF64_ST_BIND
-#define ELF_ST_TYPE ELF64_ST_TYPE
-#define ELF_ST_INFO ELF64_ST_INFO
-
-#define AuxInfo Aux64Info
-#endif
-
+++ /dev/null
-/******************************************************************************
- * xc_evtchn.c
- *
- * API for manipulating and accessing inter-domain event channels.
- *
- * Copyright (c) 2004, K A Fraser.
- */
-
-#include "xc_private.h"
-
-
-static int do_evtchn_op(int xc_handle, evtchn_op_t *op)
-{
- int ret = -1;
- privcmd_hypercall_t hypercall;
-
- hypercall.op = __HYPERVISOR_event_channel_op;
- hypercall.arg[0] = (unsigned long)op;
-
- if ( mlock(op, sizeof(*op)) != 0 )
- {
- PERROR("Could not lock memory for Xen hypercall");
- goto out1;
- }
-
- if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
- goto out2;
-
- out2: (void)munlock(op, sizeof(*op));
- out1: return ret;
-}
-
-
-int xc_evtchn_bind_interdomain(int xc_handle,
- u32 dom1,
- u32 dom2,
- int *port1,
- int *port2)
-{
- evtchn_op_t op;
- int rc;
-
- op.cmd = EVTCHNOP_bind_interdomain;
- op.u.bind_interdomain.dom1 = (domid_t)dom1;
- op.u.bind_interdomain.dom2 = (domid_t)dom2;
-
- if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 )
- {
- if ( port1 != NULL )
- *port1 = op.u.bind_interdomain.port1;
- if ( port2 != NULL )
- *port2 = op.u.bind_interdomain.port2;
- }
-
- return rc;
-}
-
-
-int xc_evtchn_bind_virq(int xc_handle,
- int virq,
- int *port)
-{
- evtchn_op_t op;
- int rc;
-
- op.cmd = EVTCHNOP_bind_virq;
- op.u.bind_virq.virq = (u32)virq;
-
- if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 )
- {
- if ( port != NULL )
- *port = op.u.bind_virq.port;
- }
-
- return rc;
-}
-
-
-int xc_evtchn_close(int xc_handle,
- u32 dom,
- int port)
-{
- evtchn_op_t op;
- op.cmd = EVTCHNOP_close;
- op.u.close.dom = (domid_t)dom;
- op.u.close.port = port;
- return do_evtchn_op(xc_handle, &op);
-}
-
-
-int xc_evtchn_send(int xc_handle,
- int local_port)
-{
- evtchn_op_t op;
- op.cmd = EVTCHNOP_send;
- op.u.send.local_port = local_port;
- return do_evtchn_op(xc_handle, &op);
-}
-
-
-int xc_evtchn_status(int xc_handle,
- u32 dom,
- int port,
- xc_evtchn_status_t *status)
-{
- evtchn_op_t op;
- int rc;
-
- op.cmd = EVTCHNOP_status;
- op.u.status.dom = (domid_t)dom;
- op.u.status.port = port;
-
- if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 )
- {
- switch ( status->status = op.u.status.status )
- {
- case EVTCHNSTAT_interdomain:
- status->u.interdomain.dom = (u32)op.u.status.u.interdomain.dom;
- status->u.interdomain.port = op.u.status.u.interdomain.port;
- break;
- case EVTCHNSTAT_pirq:
- status->u.pirq = op.u.status.u.pirq;
- break;
- case EVTCHNSTAT_virq:
- status->u.virq = op.u.status.u.virq;
- break;
- }
- }
-
- return rc;
-}
+++ /dev/null
-#include "xc_io.h"
-
-void xcio_error(XcIOContext *ctxt, const char *msg, ...){
- va_list args;
-
- va_start(args, msg);
- IOStream_vprint(ctxt->info, msg, args);
- va_end(args);
-}
-
-void xcio_info(XcIOContext *ctxt, const char *msg, ...){
- va_list args;
-
- if(!(ctxt->flags & XCFLAGS_VERBOSE)) return;
- va_start(args, msg);
- IOStream_vprint(ctxt->info, msg, args);
- va_end(args);
-}
-
-void xcio_debug(XcIOContext *ctxt, const char *msg, ...){
- va_list args;
-
- if(!(ctxt->flags & XCFLAGS_DEBUG)) return;
- va_start(args, msg);
- IOStream_vprint(ctxt->info, msg, args);
- va_end(args);
-}
+++ /dev/null
-#ifndef __XC_XC_IO_H__
-#define __XC_XC_IO_H__
-
-#include "xc_private.h"
-#include "iostream.h"
-
-typedef struct XcIOContext {
- u32 domain;
- unsigned flags;
- IOStream *io;
- IOStream *info;
- IOStream *err;
- char *vmconfig;
- int vmconfig_n;
-} XcIOContext;
-
-static inline int xcio_read(XcIOContext *ctxt, void *buf, int n){
- int rc;
-
- rc = IOStream_read(ctxt->io, buf, n);
- return (rc == n ? 0 : rc);
-}
-
-static inline int xcio_write(XcIOContext *ctxt, void *buf, int n){
- int rc;
-
- rc = IOStream_write(ctxt->io, buf, n);
- return (rc == n ? 0 : rc);
-}
-
-static inline int xcio_flush(XcIOContext *ctxt){
- return IOStream_flush(ctxt->io);
-}
-
-extern void xcio_error(XcIOContext *ctxt, const char *msg, ...);
-extern void xcio_info(XcIOContext *ctxt, const char *msg, ...);
-
-#define xcio_perror(_ctxt, _msg...) \
-xcio_error(_ctxt, "(errno %d %s)" _msg, errno, strerror(errno), ## _msg)
-
-#endif /* ! __XC_XC_IO_H__ */
-
-
-
+++ /dev/null
-/******************************************************************************
- * xc_linux_build.c
- */
-
-#include "xc_private.h"
-#define ELFSIZE 32
-#include "xc_elf.h"
-#include <zlib.h>
-
-#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
-#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
-
-#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
-#define round_pgdown(_p) ((_p)&PAGE_MASK)
-
-static int readelfimage_base_and_size(char *elfbase,
- unsigned long elfsize,
- unsigned long *pkernstart,
- unsigned long *pkernend,
- unsigned long *pkernentry);
-static int loadelfimage(char *elfbase, int pmh, unsigned long *parray,
- unsigned long vstart);
-
-static long get_tot_pages(int xc_handle, u32 domid)
-{
- dom0_op_t op;
- op.cmd = DOM0_GETDOMAININFO;
- op.u.getdomaininfo.domain = (domid_t)domid;
- op.u.getdomaininfo.ctxt = NULL;
- return (do_dom0_op(xc_handle, &op) < 0) ?
- -1 : op.u.getdomaininfo.tot_pages;
-}
-
-static int get_pfn_list(int xc_handle,
- u32 domid,
- unsigned long *pfn_buf,
- unsigned long max_pfns)
-{
- dom0_op_t op;
- int ret;
- op.cmd = DOM0_GETMEMLIST;
- op.u.getmemlist.domain = (domid_t)domid;
- op.u.getmemlist.max_pfns = max_pfns;
- op.u.getmemlist.buffer = pfn_buf;
-
- if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
- return -1;
-
- ret = do_dom0_op(xc_handle, &op);
-
- (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
-
- return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
-}
-
-static int copy_to_domain_page(int pm_handle,
- unsigned long dst_pfn,
- void *src_page)
-{
- void *vaddr = map_pfn_writeable(pm_handle, dst_pfn);
- if ( vaddr == NULL )
- return -1;
- memcpy(vaddr, src_page, PAGE_SIZE);
- unmap_pfn(pm_handle, vaddr);
- return 0;
-}
-
-static int setup_guestos(int xc_handle,
- u32 dom,
- char *image, unsigned long image_size,
- gzFile initrd_gfd, unsigned long initrd_len,
- unsigned long nr_pages,
- unsigned long *pvsi, unsigned long *pvke,
- full_execution_context_t *ctxt,
- const char *cmdline,
- unsigned long shared_info_frame,
- unsigned int control_evtchn,
- unsigned long flags)
-{
- l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
- l2_pgentry_t *vl2tab=NULL, *vl2e=NULL;
- unsigned long *page_array = NULL;
- unsigned long l2tab;
- unsigned long l1tab;
- unsigned long count, i;
- extended_start_info_t *start_info;
- shared_info_t *shared_info;
- mmu_t *mmu = NULL;
- int pm_handle=-1, rc;
-
- unsigned long nr_pt_pages;
- unsigned long ppt_alloc;
- unsigned long *physmap, *physmap_e, physmap_pfn;
-
- unsigned long v_start;
- unsigned long vkern_start;
- unsigned long vkern_entry;
- unsigned long vkern_end;
- unsigned long vinitrd_start;
- unsigned long vinitrd_end;
- unsigned long vphysmap_start;
- unsigned long vphysmap_end;
- unsigned long vstartinfo_start;
- unsigned long vstartinfo_end;
- unsigned long vstack_start;
- unsigned long vstack_end;
- unsigned long vpt_start;
- unsigned long vpt_end;
- unsigned long v_end;
-
- rc = readelfimage_base_and_size(image, image_size,
- &vkern_start, &vkern_end, &vkern_entry);
- if ( rc != 0 )
- goto error_out;
-
- /*
- * Why do we need this? The number of page-table frames depends on the
- * size of the bootstrap address space. But the size of the address space
- * depends on the number of page-table frames (since each one is mapped
- * read-only). We have a pair of simultaneous equations in two unknowns,
- * which we solve by exhaustive search.
- */
- for ( nr_pt_pages = 2; ; nr_pt_pages++ )
- {
- v_start = vkern_start & ~((1<<22)-1);
- vinitrd_start = round_pgup(vkern_end);
- vinitrd_end = vinitrd_start + initrd_len;
- vphysmap_start = round_pgup(vinitrd_end);
- vphysmap_end = vphysmap_start + (nr_pages * sizeof(unsigned long));
- vpt_start = round_pgup(vphysmap_end);
- vpt_end = vpt_start + (nr_pt_pages * PAGE_SIZE);
- vstartinfo_start = vpt_end;
- vstartinfo_end = vstartinfo_start + PAGE_SIZE;
- vstack_start = vstartinfo_end;
- vstack_end = vstack_start + PAGE_SIZE;
- v_end = (vstack_end + (1<<22)-1) & ~((1<<22)-1);
- if ( (v_end - vstack_end) < (512 << 10) )
- v_end += 1 << 22; /* Add extra 4MB to get >= 512kB padding. */
- if ( (((v_end - v_start) >> L2_PAGETABLE_SHIFT) + 1) <= nr_pt_pages )
- break;
- }
-
- if ( (v_end - v_start) > (nr_pages * PAGE_SIZE) )
- {
- printf("Initial guest OS requires too much space\n"
- "(%luMB is greater than %luMB limit)\n",
- (v_end-v_start)>>20, (nr_pages<<PAGE_SHIFT)>>20);
- goto error_out;
- }
-
- printf("VIRTUAL MEMORY ARRANGEMENT:\n"
- " Loaded kernel: %08lx->%08lx\n"
- " Init. ramdisk: %08lx->%08lx\n"
- " Phys-Mach map: %08lx->%08lx\n"
- " Page tables: %08lx->%08lx\n"
- " Start info: %08lx->%08lx\n"
- " Boot stack: %08lx->%08lx\n"
- " TOTAL: %08lx->%08lx\n",
- vkern_start, vkern_end,
- vinitrd_start, vinitrd_end,
- vphysmap_start, vphysmap_end,
- vpt_start, vpt_end,
- vstartinfo_start, vstartinfo_end,
- vstack_start, vstack_end,
- v_start, v_end);
- printf(" ENTRY ADDRESS: %08lx\n", vkern_entry);
-
- if ( (pm_handle = init_pfn_mapper((domid_t)dom)) < 0 )
- goto error_out;
-
- if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
- {
- PERROR("Could not allocate memory");
- goto error_out;
- }
-
- if ( get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages )
- {
- PERROR("Could not get the page frame list");
- goto error_out;
- }
-
- loadelfimage(image, pm_handle, page_array, v_start);
-
- /* Load the initial ramdisk image. */
- if ( initrd_len != 0 )
- {
- for ( i = (vinitrd_start - v_start);
- i < (vinitrd_end - v_start); i += PAGE_SIZE )
- {
- char page[PAGE_SIZE];
- if ( gzread(initrd_gfd, page, PAGE_SIZE) == -1 )
- {
- PERROR("Error reading initrd image, could not");
- goto error_out;
- }
- copy_to_domain_page(pm_handle,
- page_array[i>>PAGE_SHIFT], page);
- }
- }
-
- if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL )
- goto error_out;
-
- /* First allocate page for page dir. */
- ppt_alloc = (vpt_start - v_start) >> PAGE_SHIFT;
- l2tab = page_array[ppt_alloc++] << PAGE_SHIFT;
- ctxt->pt_base = l2tab;
-
- /* Initialise the page tables. */
- if ( (vl2tab = map_pfn_writeable(pm_handle, l2tab >> PAGE_SHIFT)) == NULL )
- goto error_out;
- memset(vl2tab, 0, PAGE_SIZE);
- vl2e = &vl2tab[l2_table_offset(v_start)];
- for ( count = 0; count < ((v_end-v_start)>>PAGE_SHIFT); count++ )
- {
- if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
- {
- l1tab = page_array[ppt_alloc++] << PAGE_SHIFT;
- if ( vl1tab != NULL )
- unmap_pfn(pm_handle, vl1tab);
- if ( (vl1tab = map_pfn_writeable(pm_handle,
- l1tab >> PAGE_SHIFT)) == NULL )
- goto error_out;
- memset(vl1tab, 0, PAGE_SIZE);
- vl1e = &vl1tab[l1_table_offset(v_start + (count<<PAGE_SHIFT))];
- *vl2e++ = l1tab | L2_PROT;
- }
-
- *vl1e = (page_array[count] << PAGE_SHIFT) | L1_PROT;
- if ( (count >= ((vpt_start-v_start)>>PAGE_SHIFT)) &&
- (count < ((vpt_end -v_start)>>PAGE_SHIFT)) )
- *vl1e &= ~_PAGE_RW;
- vl1e++;
- }
- unmap_pfn(pm_handle, vl1tab);
- unmap_pfn(pm_handle, vl2tab);
-
- /* Write the phys->machine and machine->phys table entries. */
- physmap_pfn = (vphysmap_start - v_start) >> PAGE_SHIFT;
- physmap = physmap_e =
- map_pfn_writeable(pm_handle, page_array[physmap_pfn++]);
- for ( count = 0; count < nr_pages; count++ )
- {
- if ( add_mmu_update(xc_handle, mmu,
- (page_array[count] << PAGE_SHIFT) |
- MMU_MACHPHYS_UPDATE, count) )
- goto error_out;
- *physmap_e++ = page_array[count];
- if ( ((unsigned long)physmap_e & (PAGE_SIZE-1)) == 0 )
- {
- unmap_pfn(pm_handle, physmap);
- physmap = physmap_e =
- map_pfn_writeable(pm_handle, page_array[physmap_pfn++]);
- }
- }
- unmap_pfn(pm_handle, physmap);
-
- /*
- * Pin down l2tab addr as page dir page - causes hypervisor to provide
- * correct protection for the page
- */
- if ( add_mmu_update(xc_handle, mmu,
- l2tab | MMU_EXTENDED_COMMAND, MMUEXT_PIN_L2_TABLE) )
- goto error_out;
-
- start_info = map_pfn_writeable(
- pm_handle, page_array[(vstartinfo_start-v_start)>>PAGE_SHIFT]);
- memset(start_info, 0, sizeof(*start_info));
- start_info->nr_pages = nr_pages;
- start_info->shared_info = shared_info_frame << PAGE_SHIFT;
- start_info->flags = flags;
- start_info->pt_base = vpt_start;
- start_info->nr_pt_frames = nr_pt_pages;
- start_info->mfn_list = vphysmap_start;
- start_info->domain_controller_evtchn = control_evtchn;
- if ( initrd_len != 0 )
- {
- start_info->mod_start = vinitrd_start;
- start_info->mod_len = initrd_len;
- }
- strncpy(start_info->cmd_line, cmdline, MAX_CMDLINE);
- start_info->cmd_line[MAX_CMDLINE-1] = '\0';
- unmap_pfn(pm_handle, start_info);
-
- /* shared_info page starts its life empty. */
- shared_info = map_pfn_writeable(pm_handle, shared_info_frame);
- memset(shared_info, 0, sizeof(shared_info_t));
- /* Mask all upcalls... */
- for ( i = 0; i < MAX_VIRT_CPUS; i++ )
- shared_info->vcpu_data[i].evtchn_upcall_mask = 1;
- unmap_pfn(pm_handle, shared_info);
-
- /* Send the page update requests down to the hypervisor. */
- if ( finish_mmu_updates(xc_handle, mmu) )
- goto error_out;
-
- free(mmu);
- (void)close_pfn_mapper(pm_handle);
- free(page_array);
-
- *pvsi = vstartinfo_start;
- *pvke = vkern_entry;
-
- return 0;
-
- error_out:
- if ( mmu != NULL )
- free(mmu);
- if ( pm_handle >= 0 )
- (void)close_pfn_mapper(pm_handle);
- if ( page_array != NULL )
- free(page_array);
- return -1;
-}
-
-static unsigned long get_filesz(int fd)
-{
- u16 sig;
- u32 _sz = 0;
- unsigned long sz;
-
- lseek(fd, 0, SEEK_SET);
- read(fd, &sig, sizeof(sig));
- sz = lseek(fd, 0, SEEK_END);
- if ( sig == 0x8b1f ) /* GZIP signature? */
- {
- lseek(fd, -4, SEEK_END);
- read(fd, &_sz, 4);
- sz = _sz;
- }
- lseek(fd, 0, SEEK_SET);
-
- return sz;
-}
-
-static char *read_kernel_image(const char *filename, unsigned long *size)
-{
- int kernel_fd = -1;
- gzFile kernel_gfd = NULL;
- char *image = NULL;
- unsigned int bytes;
-
- if ( (kernel_fd = open(filename, O_RDONLY)) < 0 )
- {
- PERROR("Could not open kernel image");
- goto out;
- }
-
- *size = get_filesz(kernel_fd);
-
- if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
- {
- PERROR("Could not allocate decompression state for state file");
- goto out;
- }
-
- if ( (image = malloc(*size)) == NULL )
- {
- PERROR("Could not allocate memory for kernel image");
- goto out;
- }
-
- if ( (bytes = gzread(kernel_gfd, image, *size)) != *size )
- {
- PERROR("Error reading kernel image, could not"
- " read the whole image (%d != %ld).", bytes, *size);
- free(image);
- image = NULL;
- }
-
- out:
- if ( kernel_gfd != NULL )
- gzclose(kernel_gfd);
- else if ( kernel_fd >= 0 )
- close(kernel_fd);
- return image;
-}
-
-int xc_linux_build(int xc_handle,
- u32 domid,
- const char *image_name,
- const char *ramdisk_name,
- const char *cmdline,
- unsigned int control_evtchn,
- unsigned long flags)
-{
- dom0_op_t launch_op, op;
- int initrd_fd = -1;
- gzFile initrd_gfd = NULL;
- int rc, i;
- full_execution_context_t st_ctxt, *ctxt = &st_ctxt;
- unsigned long nr_pages;
- char *image = NULL;
- unsigned long image_size, initrd_size=0;
- unsigned long vstartinfo_start, vkern_entry;
-
- if ( (nr_pages = get_tot_pages(xc_handle, domid)) < 0 )
- {
- PERROR("Could not find total pages for domain");
- goto error_out;
- }
-
- if ( (image = read_kernel_image(image_name, &image_size)) == NULL )
- goto error_out;
-
- if ( (ramdisk_name != NULL) && (strlen(ramdisk_name) != 0) )
- {
- if ( (initrd_fd = open(ramdisk_name, O_RDONLY)) < 0 )
- {
- PERROR("Could not open the initial ramdisk image");
- goto error_out;
- }
-
- initrd_size = get_filesz(initrd_fd);
-
- if ( (initrd_gfd = gzdopen(initrd_fd, "rb")) == NULL )
- {
- PERROR("Could not allocate decompression state for initrd");
- goto error_out;
- }
- }
-
- if ( mlock(&st_ctxt, sizeof(st_ctxt) ) )
- {
- PERROR("Unable to mlock ctxt");
- return 1;
- }
-
- op.cmd = DOM0_GETDOMAININFO;
- op.u.getdomaininfo.domain = (domid_t)domid;
- op.u.getdomaininfo.ctxt = ctxt;
- if ( (do_dom0_op(xc_handle, &op) < 0) ||
- ((u32)op.u.getdomaininfo.domain != domid) )
- {
- PERROR("Could not get info on domain");
- goto error_out;
- }
- if ( !(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED) ||
- (ctxt->pt_base != 0) )
- {
- ERROR("Domain is already constructed");
- goto error_out;
- }
-
- if ( setup_guestos(xc_handle, domid, image, image_size,
- initrd_gfd, initrd_size, nr_pages,
- &vstartinfo_start, &vkern_entry,
- ctxt, cmdline,
- op.u.getdomaininfo.shared_info_frame,
- control_evtchn, flags) < 0 )
- {
- ERROR("Error constructing guest OS");
- goto error_out;
- }
-
- if ( initrd_fd >= 0 )
- close(initrd_fd);
- if ( initrd_gfd )
- gzclose(initrd_gfd);
- if ( image != NULL )
- free(image);
-
- ctxt->flags = 0;
-
- /*
- * Initial register values:
- * DS,ES,FS,GS = FLAT_GUESTOS_DS
- * CS:EIP = FLAT_GUESTOS_CS:start_pc
- * SS:ESP = FLAT_GUESTOS_DS:start_stack
- * ESI = start_info
- * [EAX,EBX,ECX,EDX,EDI,EBP are zero]
- * EFLAGS = IF | 2 (bit 1 is reserved and should always be 1)
- */
- ctxt->cpu_ctxt.ds = FLAT_GUESTOS_DS;
- ctxt->cpu_ctxt.es = FLAT_GUESTOS_DS;
- ctxt->cpu_ctxt.fs = FLAT_GUESTOS_DS;
- ctxt->cpu_ctxt.gs = FLAT_GUESTOS_DS;
- ctxt->cpu_ctxt.ss = FLAT_GUESTOS_DS;
- ctxt->cpu_ctxt.cs = FLAT_GUESTOS_CS;
- ctxt->cpu_ctxt.eip = vkern_entry;
- ctxt->cpu_ctxt.esp = vstartinfo_start;
- ctxt->cpu_ctxt.esi = vstartinfo_start;
- ctxt->cpu_ctxt.eflags = (1<<9) | (1<<2);
-
- /* FPU is set up to default initial state. */
- memset(ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
-
- /* Virtual IDT is empty at start-of-day. */
- for ( i = 0; i < 256; i++ )
- {
- ctxt->trap_ctxt[i].vector = i;
- ctxt->trap_ctxt[i].cs = FLAT_GUESTOS_CS;
- }
- ctxt->fast_trap_idx = 0;
-
- /* No LDT. */
- ctxt->ldt_ents = 0;
-
- /* Use the default Xen-provided GDT. */
- ctxt->gdt_ents = 0;
-
- /* Ring 1 stack is the initial stack. */
- ctxt->guestos_ss = FLAT_GUESTOS_DS;
- ctxt->guestos_esp = vstartinfo_start;
-
- /* No debugging. */
- memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
-
- /* No callback handlers. */
- ctxt->event_callback_cs = FLAT_GUESTOS_CS;
- ctxt->event_callback_eip = 0;
- ctxt->failsafe_callback_cs = FLAT_GUESTOS_CS;
- ctxt->failsafe_callback_eip = 0;
-
- memset( &launch_op, 0, sizeof(launch_op) );
-
- launch_op.u.builddomain.domain = (domid_t)domid;
- launch_op.u.builddomain.ctxt = ctxt;
-
- launch_op.cmd = DOM0_BUILDDOMAIN;
- rc = do_dom0_op(xc_handle, &launch_op);
-
- return rc;
-
- error_out:
- if ( initrd_gfd != NULL )
- gzclose(initrd_gfd);
- else if ( initrd_fd >= 0 )
- close(initrd_fd);
- if ( image != NULL )
- free(image);
-
- return -1;
-}
-
-static inline int is_loadable_phdr(Elf_Phdr *phdr)
-{
- return ((phdr->p_type == PT_LOAD) &&
- ((phdr->p_flags & (PF_W|PF_X)) != 0));
-}
-
-static int readelfimage_base_and_size(char *elfbase,
- unsigned long elfsize,
- unsigned long *pkernstart,
- unsigned long *pkernend,
- unsigned long *pkernentry)
-{
- Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
- Elf_Phdr *phdr;
- Elf_Shdr *shdr;
- unsigned long kernstart = ~0UL, kernend=0UL;
- char *shstrtab, *guestinfo;
- int h;
-
- if ( !IS_ELF(*ehdr) )
- {
- ERROR("Kernel image does not have an ELF header.");
- return -EINVAL;
- }
-
- if ( (ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize)) > elfsize )
- {
- ERROR("ELF program headers extend beyond end of image.");
- return -EINVAL;
- }
-
- if ( (ehdr->e_shoff + (ehdr->e_shnum * ehdr->e_shentsize)) > elfsize )
- {
- ERROR("ELF section headers extend beyond end of image.");
- return -EINVAL;
- }
-
- /* Find the section-header strings table. */
- if ( ehdr->e_shstrndx == SHN_UNDEF )
- {
- ERROR("ELF image has no section-header strings table (shstrtab).");
- return -EINVAL;
- }
- shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff +
- (ehdr->e_shstrndx*ehdr->e_shentsize));
- shstrtab = elfbase + shdr->sh_offset;
-
- /* Find the special '__xen_guest' section and check its contents. */
- for ( h = 0; h < ehdr->e_shnum; h++ )
- {
- shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff + (h*ehdr->e_shentsize));
- if ( strcmp(&shstrtab[shdr->sh_name], "__xen_guest") != 0 )
- continue;
- guestinfo = elfbase + shdr->sh_offset;
- if ( (strstr(guestinfo, "GUEST_OS=linux") == NULL) ||
- (strstr(guestinfo, "XEN_VER=1.3") == NULL) )
- {
- ERROR("Will only load Linux images built for Xen v1.3");
- ERROR("Actually saw: '%s'", guestinfo);
- return -EINVAL;
- }
- break;
- }
- if ( h == ehdr->e_shnum )
- {
- ERROR("Not a Xen-ELF image: '__xen_guest' section not found.");
- return -EINVAL;
- }
-
- for ( h = 0; h < ehdr->e_phnum; h++ )
- {
- phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
- if ( !is_loadable_phdr(phdr) )
- continue;
- if ( phdr->p_vaddr < kernstart )
- kernstart = phdr->p_vaddr;
- if ( (phdr->p_vaddr + phdr->p_memsz) > kernend )
- kernend = phdr->p_vaddr + phdr->p_memsz;
- }
-
- if ( (kernstart > kernend) ||
- (ehdr->e_entry < kernstart) ||
- (ehdr->e_entry > kernend) )
- {
- ERROR("Malformed ELF image.");
- return -EINVAL;
- }
-
- *pkernstart = kernstart;
- *pkernend = kernend;
- *pkernentry = ehdr->e_entry;
-
- return 0;
-}
-
-static int loadelfimage(char *elfbase, int pmh, unsigned long *parray,
- unsigned long vstart)
-{
- Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
- Elf_Phdr *phdr;
- int h;
-
- char *va;
- unsigned long pa, done, chunksz;
-
- for ( h = 0; h < ehdr->e_phnum; h++ )
- {
- phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
- if ( !is_loadable_phdr(phdr) )
- continue;
-
- for ( done = 0; done < phdr->p_filesz; done += chunksz )
- {
- pa = (phdr->p_vaddr + done) - vstart;
- va = map_pfn_writeable(pmh, parray[pa>>PAGE_SHIFT]);
- va += pa & (PAGE_SIZE-1);
- chunksz = phdr->p_filesz - done;
- if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
- chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
- memcpy(va, elfbase + phdr->p_offset + done, chunksz);
- unmap_pfn(pmh, va);
- }
-
- for ( ; done < phdr->p_memsz; done += chunksz )
- {
- pa = (phdr->p_vaddr + done) - vstart;
- va = map_pfn_writeable(pmh, parray[pa>>PAGE_SHIFT]);
- va += pa & (PAGE_SIZE-1);
- chunksz = phdr->p_memsz - done;
- if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
- chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
- memset(va, 0, chunksz);
- unmap_pfn(pmh, va);
- }
- }
-
- return 0;
-}
-
+++ /dev/null
-/******************************************************************************
- * xc_linux_restore.c
- *
- * Restore the state of a Linux session.
- *
- * Copyright (c) 2003, K A Fraser.
- */
-
-#include "xc_private.h"
-#include <asm-xen/suspend.h>
-
-#define MAX_BATCH_SIZE 1024
-
-#define DEBUG 0
-
-#if DEBUG
-#define DPRINTF(_f, _a...) printf ( _f , ## _a )
-#else
-#define DPRINTF(_f, _a...) ((void)0)
-#endif
-
-
-static int get_pfn_list(int xc_handle,
- u32 domain_id,
- unsigned long *pfn_buf,
- unsigned long max_pfns)
-{
- dom0_op_t op;
- int ret;
- op.cmd = DOM0_GETMEMLIST;
- op.u.getmemlist.domain = (domid_t)domain_id;
- op.u.getmemlist.max_pfns = max_pfns;
- op.u.getmemlist.buffer = pfn_buf;
-
- if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
- {
- PERROR("Could not lock pfn list buffer");
- return -1;
- }
-
- ret = do_dom0_op(xc_handle, &op);
-
- (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
-
- return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
-}
-
-/** Read the vmconfig string from the state input.
- * It is stored as a 4-byte count 'n' followed by n bytes.
- * The config data is stored in a new string in 'ioctxt->vmconfig',
- * and is null-terminated. The count is stored in 'ioctxt->vmconfig_n'.
- *
- * @param ioctxt i/o context
- * @return 0 on success, non-zero on error.
- */
-static int read_vmconfig(XcIOContext *ioctxt){
- int err = -1;
- if(xcio_read(ioctxt, &ioctxt->vmconfig_n, sizeof(ioctxt->vmconfig_n))){
- goto exit;
- }
- ioctxt->vmconfig = malloc(ioctxt->vmconfig_n + 1);
- if(!ioctxt->vmconfig) goto exit;
- if(xcio_read(ioctxt, ioctxt->vmconfig, ioctxt->vmconfig_n)){
- goto exit;
- }
- ioctxt->vmconfig[ioctxt->vmconfig_n] = '\0';
- err = 0;
- exit:
- if(err){
- if(ioctxt->vmconfig){
- free(ioctxt->vmconfig);
- }
- ioctxt->vmconfig = NULL;
- ioctxt->vmconfig_n = 0;
- }
- return err;
-}
-
-int xc_linux_restore(int xc_handle, XcIOContext *ioctxt)
-{
- dom0_op_t op;
- int rc = 1, i, n, k;
- unsigned long mfn, pfn, xpfn;
- unsigned int prev_pc, this_pc;
- u32 dom = ioctxt->domain;
- int verify = 0;
-
- /* Number of page frames in use by this Linux session. */
- unsigned long nr_pfns;
-
- /* The new domain's shared-info frame number. */
- unsigned long shared_info_frame;
- unsigned char shared_info[PAGE_SIZE]; /* saved contents from file */
-
- /* A copy of the CPU context of the guest. */
- full_execution_context_t ctxt;
-
- /* First 16 bytes of the state file must contain 'LinuxGuestRecord'. */
- char signature[16];
-
- /* A copy of the domain's name. */
- char name[MAX_DOMAIN_NAME];
-
- /* A table containg the type of each PFN (/not/ MFN!). */
- unsigned long *pfn_type = NULL;
-
- /* A table of MFNs to map in the current region */
- unsigned long *region_mfn = NULL;
-
- /* A temporary mapping, and a copy, of one frame of guest memory. */
- unsigned long *ppage;
-
- /* A copy of the pfn-to-mfn table frame list. */
- unsigned long pfn_to_mfn_frame_list[1024];
-
- /* A table mapping each PFN to its new MFN. */
- unsigned long *pfn_to_mfn_table = NULL;
-
- /* used by mapper for updating the domain's copy of the table */
- unsigned long *live_pfn_to_mfn_table = NULL;
-
- /* A temporary mapping of the guest's suspend record. */
- suspend_record_t *p_srec;
-
- char *region_base;
-
- mmu_t *mmu = NULL;
-
- int pm_handle = -1;
-
- /* used by debug verify code */
- unsigned long buf[PAGE_SIZE/sizeof(unsigned long)];
-
- if ( mlock(&ctxt, sizeof(ctxt) ) ) {
- /* needed for when we do the build dom0 op,
- but might as well do early */
- PERROR("Unable to mlock ctxt");
- return 1;
- }
-
- /* Start writing out the saved-domain record. */
- if ( xcio_read(ioctxt, signature, 16) ||
- (memcmp(signature, "LinuxGuestRecord", 16) != 0) ) {
- xcio_error(ioctxt, "Unrecognised state format -- no signature found");
- goto out;
- }
-
- if ( xcio_read(ioctxt, name, sizeof(name)) ||
- xcio_read(ioctxt, &nr_pfns, sizeof(unsigned long)) ||
- xcio_read(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) ) {
- xcio_error(ioctxt, "Error reading header");
- goto out;
- }
-
- if(read_vmconfig(ioctxt)){
- xcio_error(ioctxt, "Error writing vmconfig");
- goto out;
- }
-
- for ( i = 0; i < MAX_DOMAIN_NAME; i++ ) {
- if ( name[i] == '\0' ) break;
- if ( name[i] & 0x80 )
- {
- xcio_error(ioctxt, "Random characters in domain name");
- goto out;
- }
- }
- name[MAX_DOMAIN_NAME-1] = '\0';
-
- if ( nr_pfns > 1024*1024 ) {
- xcio_error(ioctxt, "Invalid state file -- pfn count out of range");
- goto out;
- }
-
- /* We want zeroed memory so use calloc rather than malloc. */
- pfn_to_mfn_table = calloc(1, 4 * nr_pfns);
- pfn_type = calloc(1, 4 * nr_pfns);
- region_mfn = calloc(1, 4 * MAX_BATCH_SIZE);
-
- if ( (pfn_to_mfn_table == NULL) || (pfn_type == NULL) ||
- (region_mfn == NULL) ) {
- errno = ENOMEM;
- goto out;
- }
-
- if ( mlock(region_mfn, 4 * MAX_BATCH_SIZE ) ) {
- xcio_error(ioctxt, "Could not mlock region_mfn");
- goto out;
- }
-
- /* Set the domain's name to that from the restore file */
- if ( xc_domain_setname( xc_handle, dom, name ) ) {
- xcio_error(ioctxt, "Could not set domain name");
- goto out;
- }
-
- /* Set the domain's initial memory allocation
- to that from the restore file */
-
- if ( xc_domain_setinitialmem(xc_handle, dom,
- nr_pfns * (PAGE_SIZE / 1024)) )
- {
- xcio_error(ioctxt, "Could not set domain initial memory");
- goto out;
- }
-
- /* Get the domain's shared-info frame. */
- op.cmd = DOM0_GETDOMAININFO;
- op.u.getdomaininfo.domain = (domid_t)dom;
- op.u.getdomaininfo.ctxt = NULL;
- if ( do_dom0_op(xc_handle, &op) < 0 ) {
- xcio_error(ioctxt, "Could not get information on new domain");
- goto out;
- }
- shared_info_frame = op.u.getdomaininfo.shared_info_frame;
-
- if ( (pm_handle = init_pfn_mapper((domid_t)dom)) < 0 )
- goto out;
-
-
-
- /* Build the pfn-to-mfn table. We choose MFN ordering returned by Xen. */
- if ( get_pfn_list(xc_handle, dom, pfn_to_mfn_table, nr_pfns) != nr_pfns ) {
- xcio_error(ioctxt, "Did not read correct number of frame numbers for new dom");
- goto out;
- }
-
- if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL ) {
- xcio_error(ioctxt, "Could not initialise for MMU updates");
- goto out;
- }
-
- xcio_info(ioctxt, "Reloading memory pages: 0%%");
-
- /*
- * Now simply read each saved frame into its new machine frame.
- * We uncanonicalise page tables as we go.
- */
- prev_pc = 0;
-
- n=0;
- while(1) {
- int j;
- unsigned long region_pfn_type[MAX_BATCH_SIZE];
-
- this_pc = (n * 100) / nr_pfns;
- if ( (this_pc - prev_pc) >= 5 ) {
- xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc);
- prev_pc = this_pc;
- }
-
- if ( xcio_read(ioctxt, &j, sizeof(int)) ) {
- xcio_error(ioctxt, "Error when reading from state file");
- goto out;
- }
-
- DPRINTF("batch %d\n",j);
-
- if ( j == -1 ) {
- verify = 1;
- printf("Entering page verify mode\n");
- continue;
- }
-
- if ( j == 0 ) break; /* our work here is done */
-
- if( j > MAX_BATCH_SIZE ) {
- xcio_error(ioctxt, "Max batch size exceeded. Giving up.");
- goto out;
- }
-
- if ( xcio_read(ioctxt, region_pfn_type, j*sizeof(unsigned long)) ) {
- xcio_error(ioctxt, "Error when reading from state file");
- goto out;
- }
-
- for(i=0; i<j; i++) {
- if ( (region_pfn_type[i] & LTAB_MASK) == XTAB) {
- region_mfn[i] = 0; /* we know map will fail, but don't care */
- } else {
- pfn = region_pfn_type[i] & ~LTAB_MASK;
- region_mfn[i] = pfn_to_mfn_table[pfn];
- }
- }
-
- if ( (region_base = mfn_mapper_map_batch( xc_handle, dom,
- PROT_WRITE,
- region_mfn,
- j )) == 0) {
- xcio_error(ioctxt, "map batch failed");
- goto out;
- }
-
- for(i=0;i<j;i++) {
- unsigned long *ppage;
-
- pfn = region_pfn_type[i] & ~LTAB_MASK;
-
- if ( (region_pfn_type[i] & LTAB_MASK) == XTAB) continue;
-
- if (pfn>nr_pfns) {
- xcio_error(ioctxt, "pfn out of range");
- goto out;
- }
-
- region_pfn_type[i] &= LTAB_MASK;
-
- pfn_type[pfn] = region_pfn_type[i];
-
- mfn = pfn_to_mfn_table[pfn];
-
- if ( verify ) {
- ppage = (unsigned long*) buf; /* debug case */
- } else {
- ppage = (unsigned long*) (region_base + i*PAGE_SIZE);
- }
-
- if ( xcio_read(ioctxt, ppage, PAGE_SIZE) ) {
- xcio_error(ioctxt, "Error when reading from state file");
- goto out;
- }
-
- switch( region_pfn_type[i] ) {
- case 0:
- break;
-
- case L1TAB:
- {
- for ( k = 0; k < 1024; k++ ) {
- if ( ppage[k] & _PAGE_PRESENT ) {
- xpfn = ppage[k] >> PAGE_SHIFT;
-
- if ( xpfn >= nr_pfns ) {
- xcio_error(ioctxt, "Frame number in type %lu page table is "
- "out of range. i=%d k=%d pfn=0x%lx "
- "nr_pfns=%lu", region_pfn_type[i]>>28, i,
- k, xpfn, nr_pfns);
- goto out;
- }
-
- ppage[k] &= (PAGE_SIZE - 1) &
- ~(_PAGE_GLOBAL | _PAGE_PAT);
- ppage[k] |= pfn_to_mfn_table[xpfn] << PAGE_SHIFT;
- }
- }
- }
- break;
-
- case L2TAB:
- {
- for ( k = 0;
- k < (HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT);
- k++ ) {
- if ( ppage[k] & _PAGE_PRESENT ) {
- xpfn = ppage[k] >> PAGE_SHIFT;
-
- if ( xpfn >= nr_pfns ) {
- xcio_error(ioctxt, "Frame number in type %lu page table is "
- "out of range. i=%d k=%d pfn=%lu nr_pfns=%lu",
- region_pfn_type[i]>>28, i, k, xpfn, nr_pfns);
-
- goto out;
- }
-
- ppage[k] &= (PAGE_SIZE - 1) &
- ~(_PAGE_GLOBAL | _PAGE_PSE);
- ppage[k] |= pfn_to_mfn_table[xpfn] << PAGE_SHIFT;
- }
- }
- }
- break;
-
- default:
- xcio_error(ioctxt, "Bogus page type %lx page table is out of range."
- " i=%d nr_pfns=%lu", region_pfn_type[i], i, nr_pfns);
- goto out;
-
- } /* end of page type switch statement */
-
- if ( verify ) {
- int res = memcmp(buf, (region_base + i*PAGE_SIZE), PAGE_SIZE );
- if (res) {
- int v;
- printf("************** pfn=%lx type=%lx gotcs=%08lx "
- "actualcs=%08lx\n", pfn, pfn_type[pfn],
- csum_page(region_base + i*PAGE_SIZE),
- csum_page(buf));
- for ( v = 0; v < 4; v++ ) {
- unsigned long *p = (unsigned long *)
- (region_base + i*PAGE_SIZE);
- if ( buf[v] != p[v] )
- printf(" %d: %08lx %08lx\n",
- v, buf[v], p[v] );
- }
- }
- }
-
- if ( add_mmu_update(xc_handle, mmu,
- (mfn<<PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, pfn) ) {
- printf("machpys mfn=%ld pfn=%ld\n",mfn,pfn);
- goto out;
- }
-
- } /* end of 'batch' for loop */
-
- munmap( region_base, j*PAGE_SIZE );
- n+=j; /* crude stats */
- }
-
- printf("Received all pages\n");
-
- DPRINTF("Received all pages\n");
-
- /*
- * Pin page tables. Do this after writing to them as otherwise Xen
- * will barf when doing the type-checking.
- */
- for ( i = 0; i < nr_pfns; i++ ) {
- if ( pfn_type[i] == L1TAB ) {
- if ( add_mmu_update(xc_handle, mmu,
- (pfn_to_mfn_table[i]<<PAGE_SHIFT) |
- MMU_EXTENDED_COMMAND,
- MMUEXT_PIN_L1_TABLE) ) {
- printf("ERR pin L1 pfn=%lx mfn=%lx\n",
- (unsigned long)i, pfn_to_mfn_table[i]);
- goto out;
- }
- } else if ( pfn_type[i] == L2TAB ) {
- if ( add_mmu_update(xc_handle, mmu,
- (pfn_to_mfn_table[i]<<PAGE_SHIFT) |
- MMU_EXTENDED_COMMAND,
- MMUEXT_PIN_L2_TABLE) ) {
- printf("ERR pin L2 pfn=%lx mfn=%lx\n",
- (unsigned long)i, pfn_to_mfn_table[i]);
- goto out;
- }
- }
- }
-
- if ( finish_mmu_updates(xc_handle, mmu) ) goto out;
-
- xcio_info(ioctxt, "\b\b\b\b100%%\nMemory reloaded.\n");
-
-
- if ( xcio_read(ioctxt, &ctxt, sizeof(ctxt)) ||
- xcio_read(ioctxt, shared_info, PAGE_SIZE) ) {
- xcio_error(ioctxt, "Error when reading from state file");
- goto out;
- }
-
- /* Uncanonicalise the suspend-record frame number and poke resume rec. */
- pfn = ctxt.cpu_ctxt.esi;
- if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) )
- {
- xcio_error(ioctxt, "Suspend record frame number is bad");
- goto out;
- }
- ctxt.cpu_ctxt.esi = mfn = pfn_to_mfn_table[pfn];
- p_srec = map_pfn_writeable(pm_handle, mfn);
- p_srec->resume_info.nr_pages = nr_pfns;
- p_srec->resume_info.shared_info = shared_info_frame << PAGE_SHIFT;
- p_srec->resume_info.flags = 0;
- unmap_pfn(pm_handle, p_srec);
-
- /* Uncanonicalise each GDT frame number. */
- if ( ctxt.gdt_ents > 8192 ) {
- xcio_error(ioctxt, "GDT entry count out of range");
- goto out;
- }
- for ( i = 0; i < ctxt.gdt_ents; i += 512 ) {
- pfn = ctxt.gdt_frames[i];
- if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) ) {
- xcio_error(ioctxt, "GDT frame number is bad");
- goto out;
- }
- ctxt.gdt_frames[i] = pfn_to_mfn_table[pfn];
- }
-
- /* Uncanonicalise the page table base pointer. */
- pfn = ctxt.pt_base >> PAGE_SHIFT;
- if ( (pfn >= nr_pfns) || (pfn_type[pfn] != L2TAB) ) {
- printf("PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx\n",
- pfn, nr_pfns, pfn_type[pfn], (unsigned long)L2TAB);
- xcio_error(ioctxt, "PT base is bad.");
- goto out;
- }
- ctxt.pt_base = pfn_to_mfn_table[pfn] << PAGE_SHIFT;
-
-
- /* clear any pending events and the selector */
- memset( &(((shared_info_t *)shared_info)->evtchn_pending[0]),
- 0, sizeof (((shared_info_t *)shared_info)->evtchn_pending)+
- sizeof(((shared_info_t *)shared_info)->evtchn_pending_sel) );
-
- /* Copy saved contents of shared-info page. No checking needed. */
- ppage = map_pfn_writeable(pm_handle, shared_info_frame);
- memcpy(ppage, shared_info, sizeof(shared_info_t));
- unmap_pfn(pm_handle, ppage);
-
-
- /* Uncanonicalise the pfn-to-mfn table frame-number list. */
- for ( i = 0; i < (nr_pfns+1023)/1024; i++ ) {
- unsigned long pfn, mfn;
-
- pfn = pfn_to_mfn_frame_list[i];
- if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) ) {
- xcio_error(ioctxt, "PFN-to-MFN frame number is bad");
- goto out;
- }
- mfn = pfn_to_mfn_table[pfn];
- pfn_to_mfn_frame_list[i] = mfn;
- }
-
- if ( (live_pfn_to_mfn_table =
- mfn_mapper_map_batch(xc_handle, dom,
- PROT_WRITE,
- pfn_to_mfn_frame_list,
- (nr_pfns+1023)/1024 )) == 0 ) {
- xcio_error(ioctxt, "Couldn't map pfn_to_mfn table");
- goto out;
- }
-
- memcpy( live_pfn_to_mfn_table, pfn_to_mfn_table,
- nr_pfns*sizeof(unsigned long) );
-
- munmap( live_pfn_to_mfn_table, ((nr_pfns+1023)/1024)*PAGE_SIZE );
-
- /*
- * Safety checking of saved context:
- * 1. cpu_ctxt is fine, as Xen checks that on context switch.
- * 2. fpu_ctxt is fine, as it can't hurt Xen.
- * 3. trap_ctxt needs the code selectors checked.
- * 4. fast_trap_idx is checked by Xen.
- * 5. ldt base must be page-aligned, no more than 8192 ents, ...
- * 6. gdt already done, and further checking is done by Xen.
- * 7. check that guestos_ss is safe.
- * 8. pt_base is already done.
- * 9. debugregs are checked by Xen.
- * 10. callback code selectors need checking.
- */
- for ( i = 0; i < 256; i++ ) {
- ctxt.trap_ctxt[i].vector = i;
- if ( (ctxt.trap_ctxt[i].cs & 3) == 0 )
- ctxt.trap_ctxt[i].cs = FLAT_GUESTOS_CS;
- }
- if ( (ctxt.guestos_ss & 3) == 0 ){
- ctxt.guestos_ss = FLAT_GUESTOS_DS;
- }
- if ( (ctxt.event_callback_cs & 3) == 0 ){
- ctxt.event_callback_cs = FLAT_GUESTOS_CS;
- }
- if ( (ctxt.failsafe_callback_cs & 3) == 0 ){
- ctxt.failsafe_callback_cs = FLAT_GUESTOS_CS;
- }
- if ( ((ctxt.ldt_base & (PAGE_SIZE - 1)) != 0) ||
- (ctxt.ldt_ents > 8192) ||
- (ctxt.ldt_base > HYPERVISOR_VIRT_START) ||
- ((ctxt.ldt_base + ctxt.ldt_ents*8) > HYPERVISOR_VIRT_START) )
- {
- xcio_error(ioctxt, "Bad LDT base or size");
- goto out;
- }
-
- op.cmd = DOM0_BUILDDOMAIN;
- op.u.builddomain.domain = (domid_t)dom;
- op.u.builddomain.ctxt = &ctxt;
- rc = do_dom0_op(xc_handle, &op);
-
- /* don't start the domain as we have console etc to set up */
-
- if( rc == 0 ) {
- /* Success: print the domain id. */
- xcio_info(ioctxt, "DOM=%lu\n", dom);
- return 0;
- }
-
-
- out:
- if ( (rc != 0) && (dom != 0) ){
- xc_domain_destroy(xc_handle, dom);
- }
- if ( mmu != NULL ){
- free(mmu);
- }
- if ( pm_handle >= 0 ){
- (void)close_pfn_mapper(pm_handle);
- }
- if ( pfn_to_mfn_table != NULL ){
- free(pfn_to_mfn_table);
- }
- if ( pfn_type != NULL ){
- free(pfn_type);
- }
-
- if ( rc == 0 ){
- ioctxt->domain = dom;
- }
- DPRINTF("Restore exit with rc=%d\n",rc);
- return rc;
-}
+++ /dev/null
-/******************************************************************************
- * xc_linux_save.c
- *
- * Save the state of a running Linux session.
- *
- * Copyright (c) 2003, K A Fraser.
- */
-
-#include <sys/time.h>
-#include "xc_private.h"
-#include <asm-xen/suspend.h>
-
-#define BATCH_SIZE 1024 /* 1024 pages (4MB) at a time */
-
-#define DEBUG 0
-#define DDEBUG 0
-
-#if DEBUG
-#define DPRINTF(_f, _a...) printf ( _f , ## _a )
-#else
-#define DPRINTF(_f, _a...) ((void)0)
-#endif
-
-#if DDEBUG
-#define DDPRINTF(_f, _a...) printf ( _f , ## _a )
-#else
-#define DDPRINTF(_f, _a...) ((void)0)
-#endif
-
-/*
- * Returns TRUE if the given machine frame number has a unique mapping
- * in the guest's pseudophysical map.
- * 0x80000000-3 mark the shared_info, and blk/net rings
- */
-#define MFN_IS_IN_PSEUDOPHYS_MAP(_mfn) \
- (((_mfn) < (1024*1024)) && \
- (((live_mfn_to_pfn_table[_mfn] < nr_pfns) && \
- (live_pfn_to_mfn_table[live_mfn_to_pfn_table[_mfn]] == (_mfn))) || \
- ((live_mfn_to_pfn_table[_mfn] >= 0x80000000) && \
- (live_mfn_to_pfn_table[_mfn] <= 0x80000003)) || \
- (live_pfn_to_mfn_table[live_mfn_to_pfn_table[_mfn]] == 0x80000004)))
-
-/* Returns TRUE if MFN is successfully converted to a PFN. */
-#define translate_mfn_to_pfn(_pmfn) \
-({ \
- unsigned long mfn = *(_pmfn); \
- int _res = 1; \
- if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) ) \
- _res = 0; \
- else \
- *(_pmfn) = live_mfn_to_pfn_table[mfn]; \
- _res; \
-})
-
-static inline int test_bit ( int nr, volatile void * addr)
-{
- return (((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] >>
- (nr % (sizeof(unsigned long)*8))) & 1;
-}
-
-static inline void clear_bit ( int nr, volatile void * addr)
-{
- ((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] &=
- ~(1 << (nr % (sizeof(unsigned long)*8) ) );
-}
-
-static inline void set_bit ( int nr, volatile void * addr)
-{
- ((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] |=
- (1 << (nr % (sizeof(unsigned long)*8) ) );
-}
-
-/* Returns the hamming weight (i.e. the number of bits set) in a N-bit word */
-static inline unsigned int hweight32(unsigned int w)
-{
- unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
- res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
- res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
- res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
- return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
-}
-
-static inline int count_bits ( int nr, volatile void *addr)
-{
- int i, count = 0;
- unsigned long *p = (unsigned long *)addr;
- /* We know that the array is padded to unsigned long. */
- for(i=0;i<nr/(sizeof(unsigned long)*8);i++,p++)
- count += hweight32( *p );
- return count;
-}
-
-static inline int permute( int i, int nr, int order_nr )
-{
- /* Need a simple permutation function so that we scan pages in a
- pseudo random order, enabling us to get a better estimate of
- the domain's page dirtying rate as we go (there are often
- contiguous ranges of pfns that have similar behaviour, and we
- want to mix them up. */
-
- /* e.g. nr->oder 15->4 16->4 17->5 */
- /* 512MB domain, 128k pages, order 17 */
-
- /*
- QPONMLKJIHGFEDCBA
- QPONMLKJIH
- GFEDCBA
- */
-
- /*
- QPONMLKJIHGFEDCBA
- EDCBA
- QPONM
- LKJIHGF
- */
-
- do { i = ((i>>(order_nr-10)) | ( i<<10 ) ) & ((1<<order_nr)-1); }
- while ( i >= nr ); /* this won't ever loop if nr is a power of 2 */
-
- return i;
-}
-
-static long long tv_to_us( struct timeval *new )
-{
- return (new->tv_sec * 1000000) + new->tv_usec;
-}
-
-static long long llgettimeofday()
-{
- struct timeval now;
- gettimeofday(&now, NULL);
- return tv_to_us(&now);
-}
-
-static long long tv_delta( struct timeval *new, struct timeval *old )
-{
- return ((new->tv_sec - old->tv_sec)*1000000 ) +
- (new->tv_usec - old->tv_usec);
-}
-
-static int print_stats( int xc_handle, u32 domid,
- int pages_sent, xc_shadow_control_stats_t *stats,
- int print )
-{
- static struct timeval wall_last;
- static long long d0_cpu_last;
- static long long d1_cpu_last;
-
- struct timeval wall_now;
- long long wall_delta;
- long long d0_cpu_now, d0_cpu_delta;
- long long d1_cpu_now, d1_cpu_delta;
-
- gettimeofday(&wall_now, NULL);
-
- d0_cpu_now = xc_domain_get_cpu_usage( xc_handle, 0 )/1000;
- d1_cpu_now = xc_domain_get_cpu_usage( xc_handle, domid )/1000;
-
- if ( (d0_cpu_now == -1) || (d1_cpu_now == -1) )
- printf("ARRHHH!!\n");
-
- wall_delta = tv_delta(&wall_now,&wall_last)/1000;
-
- if ( wall_delta == 0 ) wall_delta = 1;
-
- d0_cpu_delta = (d0_cpu_now - d0_cpu_last)/1000;
- d1_cpu_delta = (d1_cpu_now - d1_cpu_last)/1000;
-
- if ( print )
- printf("delta %lldms, dom0 %d%%, target %d%%, sent %dMb/s, "
- "dirtied %dMb/s\n",
- wall_delta,
- (int)((d0_cpu_delta*100)/wall_delta),
- (int)((d1_cpu_delta*100)/wall_delta),
- (int)((pages_sent*PAGE_SIZE*8)/(wall_delta*1000)),
- (int)((stats->dirty_count*PAGE_SIZE*8)/(wall_delta*1000)));
-
- d0_cpu_last = d0_cpu_now;
- d1_cpu_last = d1_cpu_now;
- wall_last = wall_now;
-
- return 0;
-}
-
-/** Write the vmconfig string.
- * It is stored as a 4-byte count 'n' followed by n bytes.
- *
- * @param ioctxt i/o context
- * @return 0 on success, non-zero on error.
- */
-static int write_vmconfig(XcIOContext *ioctxt){
- int err = -1;
- if(xcio_write(ioctxt, &ioctxt->vmconfig_n, sizeof(ioctxt->vmconfig_n))) goto exit;
- if(xcio_write(ioctxt, ioctxt->vmconfig, ioctxt->vmconfig_n)) goto exit;
- err = 0;
- exit:
- return err;
-}
-
-static int analysis_phase( int xc_handle, u32 domid,
- int nr_pfns, unsigned long *arr )
-{
- long long start, now;
- xc_shadow_control_stats_t stats;
-
- start = llgettimeofday();
-
- while ( 0 )
- {
- int i;
-
- xc_shadow_control( xc_handle, domid,
- DOM0_SHADOW_CONTROL_OP_CLEAN2,
- arr, nr_pfns, NULL);
- printf("#Flush\n");
- for ( i = 0; i < 100; i++ )
- {
- usleep(10000);
- now = llgettimeofday();
- xc_shadow_control( xc_handle, domid,
- DOM0_SHADOW_CONTROL_OP_PEEK,
- NULL, 0, &stats);
-
- printf("now= %lld faults= %ld dirty= %ld dirty_net= %ld "
- "dirty_block= %ld\n",
- ((now-start)+500)/1000,
- stats.fault_count, stats.dirty_count,
- stats.dirty_net_count, stats.dirty_block_count);
- }
- }
-
- return -1;
-}
-
-int xc_linux_save(int xc_handle, XcIOContext *ioctxt)
-{
- dom0_op_t op;
- int rc = 1, i, j, k, last_iter, iter = 0;
- unsigned long mfn;
- u32 domid = ioctxt->domain;
- int live = (ioctxt->flags & XCFLAGS_LIVE);
- int debug = (ioctxt->flags & XCFLAGS_DEBUG);
- int sent_last_iter, skip_this_iter;
-
- /* Important tuning parameters */
- int max_iters = 29; /* limit us to 30 times round loop */
- int max_factor = 3; /* never send more than 3x nr_pfns */
-
- /* The new domain's shared-info frame number. */
- unsigned long shared_info_frame;
-
- /* A copy of the CPU context of the guest. */
- full_execution_context_t ctxt;
-
- /* A copy of the domain's name. */
- char name[MAX_DOMAIN_NAME];
-
- /* A table containg the type of each PFN (/not/ MFN!). */
- unsigned long *pfn_type = NULL;
- unsigned long *pfn_batch = NULL;
-
- /* A temporary mapping, and a copy, of one frame of guest memory. */
- unsigned long page[1024];
-
- /* A copy of the pfn-to-mfn table frame list. */
- unsigned long *live_pfn_to_mfn_frame_list;
- unsigned long pfn_to_mfn_frame_list[1024];
-
- /* Live mapping of the table mapping each PFN to its current MFN. */
- unsigned long *live_pfn_to_mfn_table = NULL;
- /* Live mapping of system MFN to PFN table. */
- unsigned long *live_mfn_to_pfn_table = NULL;
-
- /* Live mapping of shared info structure */
- unsigned long *live_shinfo;
-
- /* base of the region in which domain memory is mapped */
- unsigned char *region_base = NULL;
-
- /* A temporary mapping, and a copy, of the guest's suspend record. */
- suspend_record_t *p_srec;
-
- /* number of pages we're dealing with */
- unsigned long nr_pfns;
-
- /* power of 2 order of nr_pfns */
- int order_nr;
-
- /* bitmap of pages:
- - that should be sent this iteration (unless later marked as skip);
- - to skip this iteration because already dirty;
- - to fixup by sending at the end if not already resent; */
- unsigned long *to_send, *to_skip, *to_fix;
-
- xc_shadow_control_stats_t stats;
-
- int needed_to_fix = 0;
- int total_sent = 0;
-
- if (mlock(&ctxt, sizeof(ctxt))) {
- xcio_perror(ioctxt, "Unable to mlock ctxt");
- return 1;
- }
-
- /* Ensure that the domain exists, and that it is stopped. */
- if ( xc_domain_pause(xc_handle, domid) ){
- xcio_perror(ioctxt, "Could not pause domain");
- goto out;
- }
-
- if ( xc_domain_getfullinfo( xc_handle, domid, &op, &ctxt) )
- {
- PERROR("Could not get full domain info");
- goto out;
- }
- memcpy(name, op.u.getdomaininfo.name, sizeof(name));
- shared_info_frame = op.u.getdomaininfo.shared_info_frame;
-
- /* A cheesy test to see whether the domain contains valid state. */
- if ( ctxt.pt_base == 0 ){
- xcio_error(ioctxt, "Domain is not in a valid Linux guest OS state");
- goto out;
- }
-
- /* Map the suspend-record MFN to pin it. The page must be owned by
- domid for this to succeed. */
- p_srec = mfn_mapper_map_single(xc_handle, domid,
- sizeof(*p_srec), PROT_READ,
- ctxt.cpu_ctxt.esi);
- if (!p_srec){
- xcio_error(ioctxt, "Couldn't map state record");
- goto out;
- }
-
- nr_pfns = p_srec->nr_pfns;
-
- /* cheesy sanity check */
- if ( nr_pfns > 1024*1024 ){
- xcio_error(ioctxt, "Invalid state record -- pfn count out of range");
- goto out;
- }
-
- /* the pfn_to_mfn_frame_list fits in a single page */
- live_pfn_to_mfn_frame_list =
- mfn_mapper_map_single(xc_handle, domid,
- PAGE_SIZE, PROT_READ,
- p_srec->pfn_to_mfn_frame_list );
-
- if (!live_pfn_to_mfn_frame_list){
- xcio_error(ioctxt, "Couldn't map pfn_to_mfn_frame_list");
- goto out;
- }
-
- /* Track the mfn_to_pfn table down from the domains PT */
- {
- unsigned long *pgd;
- unsigned long mfn_to_pfn_table_start_mfn;
-
- pgd = mfn_mapper_map_single(xc_handle, domid,
- PAGE_SIZE, PROT_READ,
- ctxt.pt_base>>PAGE_SHIFT);
-
- mfn_to_pfn_table_start_mfn =
- pgd[HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT]>>PAGE_SHIFT;
-
- live_mfn_to_pfn_table =
- mfn_mapper_map_single(xc_handle, ~0UL,
- PAGE_SIZE*1024, PROT_READ,
- mfn_to_pfn_table_start_mfn );
- }
-
- /* Map all the frames of the pfn->mfn table. For migrate to succeed,
- the guest must not change which frames are used for this purpose.
- (its not clear why it would want to change them, and we'll be OK
- from a safety POV anyhow. */
-
- live_pfn_to_mfn_table = mfn_mapper_map_batch(xc_handle, domid,
- PROT_READ,
- live_pfn_to_mfn_frame_list,
- (nr_pfns+1023)/1024 );
- if( !live_pfn_to_mfn_table ){
- xcio_perror(ioctxt, "Couldn't map pfn_to_mfn table");
- goto out;
- }
-
-
- /* Canonicalise the pfn-to-mfn table frame-number list. */
- memcpy( pfn_to_mfn_frame_list, live_pfn_to_mfn_frame_list, PAGE_SIZE );
- for ( i = 0; i < nr_pfns; i += 1024 ){
- if ( !translate_mfn_to_pfn(&pfn_to_mfn_frame_list[i/1024]) ){
- xcio_error(ioctxt, "Frame # in pfn-to-mfn frame list is not in pseudophys");
- goto out;
- }
- }
-
- /* At this point, we can start the domain again if we're doing a
- live suspend */
-
- if( live ){
- if ( xc_shadow_control( xc_handle, domid,
- DOM0_SHADOW_CONTROL_OP_ENABLE_LOGDIRTY,
- NULL, 0, NULL ) < 0 ) {
- xcio_error(ioctxt, "Couldn't enable shadow mode");
- goto out;
- }
-
- if ( xc_domain_unpause(xc_handle, domid) < 0 ){
- xcio_error(ioctxt, "Couldn't unpause domain");
- goto out;
- }
-
- last_iter = 0;
- sent_last_iter = 1<<20; /* 4GB of pages */
- } else{
- last_iter = 1;
- }
-
- /* calculate the power of 2 order of nr_pfns, e.g.
- 15->4 16->4 17->5 */
- for( i=nr_pfns-1, order_nr=0; i ; i>>=1, order_nr++ );
-
- /* Setup to_send bitmap */
- {
- int sz = (nr_pfns/8) + 8; /* includes slop at end of array */
-
- to_send = malloc( sz );
- to_fix = calloc( 1, sz );
- to_skip = malloc( sz );
-
- if (!to_send || !to_fix || !to_skip){
- xcio_error(ioctxt, "Couldn't allocate to_send array");
- goto out;
- }
-
- memset( to_send, 0xff, sz );
-
- if ( mlock( to_send, sz ) ){
- xcio_perror(ioctxt, "Unable to mlock to_send");
- return 1;
- }
-
- /* (to fix is local only) */
-
- if ( mlock( to_skip, sz ) ){
- xcio_perror(ioctxt, "Unable to mlock to_skip");
- return 1;
- }
-
- }
-
- analysis_phase( xc_handle, domid, nr_pfns, to_skip );
-
- /* We want zeroed memory so use calloc rather than malloc. */
- pfn_type = calloc(BATCH_SIZE, sizeof(unsigned long));
- pfn_batch = calloc(BATCH_SIZE, sizeof(unsigned long));
-
- if ( (pfn_type == NULL) || (pfn_batch == NULL) ){
- errno = ENOMEM;
- goto out;
- }
-
- if ( mlock( pfn_type, BATCH_SIZE * sizeof(unsigned long) ) ){
- xcio_error(ioctxt, "Unable to mlock");
- goto out;
- }
-
-
- /*
- * Quick belt and braces sanity check.
- */
-#if DEBUG
- for ( i = 0; i < nr_pfns; i++ ){
- mfn = live_pfn_to_mfn_table[i];
-
- if( (live_mfn_to_pfn_table[mfn] != i) && (mfn != 0x80000004) )
- printf("i=0x%x mfn=%x live_mfn_to_pfn_table=%x\n",
- i,mfn,live_mfn_to_pfn_table[mfn]);
- }
-#endif
-
- /* Map the shared info frame */
- live_shinfo = mfn_mapper_map_single(xc_handle, domid,
- PAGE_SIZE, PROT_READ,
- shared_info_frame);
-
- if (!live_shinfo){
- xcio_error(ioctxt, "Couldn't map live_shinfo");
- goto out;
- }
-
- /* Start writing out the saved-domain record. */
-
- if ( xcio_write(ioctxt, "LinuxGuestRecord", 16) ||
- xcio_write(ioctxt, name, sizeof(name)) ||
- xcio_write(ioctxt, &nr_pfns, sizeof(unsigned long)) ||
- xcio_write(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) ){
- xcio_error(ioctxt, "Error writing header");
- goto out;
- }
- if(write_vmconfig(ioctxt)){
- xcio_error(ioctxt, "Error writing vmconfig");
- goto out;
- }
-
- print_stats( xc_handle, domid, 0, &stats, 0 );
-
- /* Now write out each data page, canonicalising page tables as we go... */
-
- while(1){
- unsigned int prev_pc, sent_this_iter, N, batch;
-
- iter++;
- sent_this_iter = 0;
- skip_this_iter = 0;
- prev_pc = 0;
- N=0;
-
- xcio_info(ioctxt, "Saving memory pages: iter %d 0%%", iter);
-
- while( N < nr_pfns ){
- unsigned int this_pc = (N * 100) / nr_pfns;
-
- if ( (this_pc - prev_pc) >= 5 ){
- xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc);
- prev_pc = this_pc;
- }
-
- /* slightly wasteful to peek the whole array evey time,
- but this is fast enough for the moment. */
-
- if ( !last_iter &&
- xc_shadow_control(xc_handle, domid,
- DOM0_SHADOW_CONTROL_OP_PEEK,
- to_skip, nr_pfns, NULL) != nr_pfns ) {
- xcio_error(ioctxt, "Error peeking shadow bitmap");
- goto out;
- }
-
-
- /* load pfn_type[] with the mfn of all the pages we're doing in
- this batch. */
-
- for ( batch = 0; batch < BATCH_SIZE && N < nr_pfns ; N++ )
- {
- int n = permute(N, nr_pfns, order_nr );
-
- if ( 0 && debug ) {
- fprintf(stderr,"%d pfn= %08lx mfn= %08lx %d "
- " [mfn]= %08lx\n",
- iter, (unsigned long)n, live_pfn_to_mfn_table[n],
- test_bit(n,to_send),
- live_mfn_to_pfn_table[live_pfn_to_mfn_table[n]&
- 0xFFFFF]);
- }
-
- if ( !last_iter &&
- test_bit(n, to_send) &&
- test_bit(n, to_skip) ) {
- skip_this_iter++; /* stats keeping */
- }
-
- if ( !((test_bit(n, to_send) && !test_bit(n, to_skip)) ||
- (test_bit(n, to_send) && last_iter) ||
- (test_bit(n, to_fix) && last_iter)) ) {
- continue;
- }
-
- /* we get here if:
- 1. page is marked to_send & hasn't already been re-dirtied
- 2. (ignore to_skip in last iteration)
- 3. add in pages that still need fixup (net bufs)
- */
-
- pfn_batch[batch] = n;
- pfn_type[batch] = live_pfn_to_mfn_table[n];
-
- if( pfn_type[batch] == 0x80000004 ){
- /* not currently in pusedo-physical map -- set bit
- in to_fix that we must send this page in last_iter
- unless its sent sooner anyhow */
-
- set_bit( n, to_fix );
- if( iter>1 )
- DDPRINTF("netbuf race: iter %d, pfn %lx. mfn %lx\n",
- iter,n,pfn_type[batch]);
- continue;
- }
-
- if ( last_iter &&
- test_bit(n, to_fix) &&
- !test_bit(n, to_send) )
- {
- needed_to_fix++;
- DPRINTF("Fix! iter %d, pfn %lx. mfn %lx\n",
- iter,n,pfn_type[batch]);
- }
-
- clear_bit(n, to_fix);
-
- batch++;
- }
-
- DDPRINTF("batch %d:%d (n=%d)\n", iter, batch, n);
-
- if ( batch == 0 )
- goto skip; /* vanishingly unlikely... */
-
- if ( (region_base = mfn_mapper_map_batch(xc_handle, domid,
- PROT_READ,
- pfn_type,
- batch)) == 0 ){
- xcio_perror(ioctxt, "map batch failed");
- goto out;
- }
-
- if ( get_pfn_type_batch(xc_handle, domid, batch, pfn_type) ){
- xcio_error(ioctxt, "get_pfn_type_batch failed");
- goto out;
- }
-
- for ( j = 0; j < batch; j++ ){
- if ( (pfn_type[j] & LTAB_MASK) == XTAB ){
- DDPRINTF("type fail: page %i mfn %08lx\n",j,pfn_type[j]);
- continue;
- }
-
- if ( 0 && debug )
- fprintf(stderr, "%d pfn= %08lx mfn= %08lx [mfn]= %08lx"
- " sum= %08lx\n",
- iter,
- (pfn_type[j] & LTAB_MASK) | pfn_batch[j],
- pfn_type[j],
- live_mfn_to_pfn_table[pfn_type[j]&(~LTAB_MASK)],
- csum_page(region_base + (PAGE_SIZE*j)));
-
- /* canonicalise mfn->pfn */
- pfn_type[j] = (pfn_type[j] & LTAB_MASK) | pfn_batch[j];
- }
-
- if ( xcio_write(ioctxt, &batch, sizeof(int) ) ){
- xcio_error(ioctxt, "Error when writing to state file (2)");
- goto out;
- }
-
- if ( xcio_write(ioctxt, pfn_type, sizeof(unsigned long)*j ) ){
- xcio_error(ioctxt, "Error when writing to state file (3)");
- goto out;
- }
-
- /* entering this loop, pfn_type is now in pfns (Not mfns) */
- for( j = 0; j < batch; j++ ){
- /* write out pages in batch */
- if( (pfn_type[j] & LTAB_MASK) == XTAB){
- DDPRINTF("SKIP BOGUS page %i mfn %08lx\n",j,pfn_type[j]);
- continue;
- }
-
- if ( ((pfn_type[j] & LTAB_MASK) == L1TAB) ||
- ((pfn_type[j] & LTAB_MASK) == L2TAB) ){
- memcpy(page, region_base + (PAGE_SIZE*j), PAGE_SIZE);
-
- for ( k = 0;
- k < (((pfn_type[j] & LTAB_MASK) == L2TAB) ?
- (HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT) :
- 1024);
- k++ ){
- unsigned long pfn;
-
- if ( !(page[k] & _PAGE_PRESENT) )
- continue;
-
- mfn = page[k] >> PAGE_SHIFT;
- pfn = live_mfn_to_pfn_table[mfn];
-
- if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
- {
- /* I don't think this should ever happen */
- printf("FNI %d : [%08lx,%d] pte=%08lx, "
- "mfn=%08lx, pfn=%08lx [mfn]=%08lx\n",
- j, pfn_type[j], k,
- page[k], mfn, live_mfn_to_pfn_table[mfn],
- (live_mfn_to_pfn_table[mfn]<nr_pfns)?
- live_pfn_to_mfn_table[
- live_mfn_to_pfn_table[mfn]] :
- 0xdeadbeef);
-
- pfn = 0; /* be suspicious */
- }
-
- page[k] &= PAGE_SIZE - 1;
- page[k] |= pfn << PAGE_SHIFT;
-
-#if 0
- printf("L%d i=%d pfn=%d mfn=%d k=%d pte=%08lx "
- "xpfn=%d\n",
- pfn_type[j]>>28,
- j,i,mfn,k,page[k],page[k]>>PAGE_SHIFT);
-#endif
-
- } /* end of page table rewrite for loop */
-
- if ( xcio_write(ioctxt, page, PAGE_SIZE) ){
- xcio_error(ioctxt, "Error when writing to state file (4)");
- goto out;
- }
-
- } /* end of it's a PT page */ else { /* normal page */
-
- if ( xcio_write(ioctxt, region_base + (PAGE_SIZE*j),
- PAGE_SIZE) ){
- xcio_error(ioctxt, "Error when writing to state file (5)");
- goto out;
- }
- }
- } /* end of the write out for this batch */
-
- sent_this_iter += batch;
-
- } /* end of this while loop for this iteration */
-
- munmap(region_base, batch*PAGE_SIZE);
-
- skip:
-
- total_sent += sent_this_iter;
-
- xcio_info(ioctxt, "\r %d: sent %d, skipped %d, ",
- iter, sent_this_iter, skip_this_iter );
-
- if ( last_iter ) {
- print_stats( xc_handle, domid, sent_this_iter, &stats, 1);
-
- xcio_info(ioctxt, "Total pages sent= %d (%.2fx)\n",
- total_sent, ((float)total_sent)/nr_pfns );
- xcio_info(ioctxt, "(of which %d were fixups)\n", needed_to_fix );
- }
-
- if (last_iter && debug){
- int minusone = -1;
- memset( to_send, 0xff, (nr_pfns+8)/8 );
- debug = 0;
- printf("Entering debug resend-all mode\n");
-
- /* send "-1" to put receiver into debug mode */
- if ( xcio_write(ioctxt, &minusone, sizeof(int)) )
- {
- xcio_error(ioctxt, "Error when writing to state file (6)");
- goto out;
- }
-
- continue;
- }
-
- if ( last_iter ) break;
-
- if ( live )
- {
- if (
- /* ( sent_this_iter > (sent_last_iter * 0.95) ) || */
- (iter >= max_iters) ||
- (sent_this_iter+skip_this_iter < 50) ||
- (total_sent > nr_pfns*max_factor) )
- {
- DPRINTF("Start last iteration\n");
- last_iter = 1;
-
- xc_domain_pause( xc_handle, domid );
- }
-
- if ( xc_shadow_control( xc_handle, domid,
- DOM0_SHADOW_CONTROL_OP_CLEAN2,
- to_send, nr_pfns, &stats ) != nr_pfns )
- {
- xcio_error(ioctxt, "Error flushing shadow PT");
- goto out;
- }
-
- sent_last_iter = sent_this_iter;
-
- print_stats( xc_handle, domid, sent_this_iter, &stats, 1);
-
- }
-
-
- } /* end of while 1 */
-
- DPRINTF("All memory is saved\n");
-
- /* Success! */
- rc = 0;
-
- /* Zero terminate */
- if ( xcio_write(ioctxt, &rc, sizeof(int)) )
- {
- xcio_error(ioctxt, "Error when writing to state file (6)");
- goto out;
- }
-
- /* Get the final execution context */
- if ( xc_domain_getfullinfo( xc_handle, domid, &op, &ctxt) )
- {
- xcio_perror(ioctxt, "Could not get full domain info");
- goto out;
- }
-
- /* Canonicalise the suspend-record frame number. */
- if ( !translate_mfn_to_pfn(&ctxt.cpu_ctxt.esi) ){
- xcio_error(ioctxt, "State record is not in range of pseudophys map");
- goto out;
- }
-
- /* Canonicalise each GDT frame number. */
- for ( i = 0; i < ctxt.gdt_ents; i += 512 ) {
- if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[i]) ) {
- xcio_error(ioctxt, "GDT frame is not in range of pseudophys map");
- goto out;
- }
- }
-
- /* Canonicalise the page table base pointer. */
- if ( !MFN_IS_IN_PSEUDOPHYS_MAP(ctxt.pt_base >> PAGE_SHIFT) ) {
- xcio_error(ioctxt, "PT base is not in range of pseudophys map");
- goto out;
- }
- ctxt.pt_base = live_mfn_to_pfn_table[ctxt.pt_base >> PAGE_SHIFT] <<
- PAGE_SHIFT;
-
- if ( xcio_write(ioctxt, &ctxt, sizeof(ctxt)) ||
- xcio_write(ioctxt, live_shinfo, PAGE_SIZE) ) {
- xcio_error(ioctxt, "Error when writing to state file (1)");
- goto out;
- }
- munmap(live_shinfo, PAGE_SIZE);
-
- out:
- if ( pfn_type != NULL ) free(pfn_type);
- DPRINTF("Save exit rc=%d\n",rc);
- return !!rc;
-
-}
+++ /dev/null
-/******************************************************************************
- * xc_misc.c
- *
- * Miscellaneous control interface functions.
- */
-
-#include "xc_private.h"
-
-int xc_interface_open(void)
-{
- int fd = open("/proc/xen/privcmd", O_RDWR);
- if ( fd == -1 )
- PERROR("Could not obtain handle on privileged command interface");
- return fd;
-}
-
-int xc_interface_close(int xc_handle)
-{
- return close(xc_handle);
-}
-
-
-#define CONSOLE_RING_CLEAR 1
-
-int xc_readconsolering(int xc_handle,
- char *str,
- unsigned int max_chars,
- int clear)
-{
- int ret;
- dom0_op_t op;
-
- op.cmd = DOM0_READCONSOLE;
- op.u.readconsole.str = (unsigned long)str;
- op.u.readconsole.count = max_chars;
- op.u.readconsole.cmd = clear ? CONSOLE_RING_CLEAR : 0;
-
- if ( (ret = mlock(str, max_chars)) != 0 )
- return ret;
-
- if ( (ret = do_dom0_op(xc_handle, &op)) >= 0 )
- str[ret] = '\0';
-
- (void)munlock(str, max_chars);
-
- return ret;
-}
-
-
-int xc_physinfo(int xc_handle,
- xc_physinfo_t *put_info)
-{
- int ret;
- dom0_op_t op;
- dom0_physinfo_t *got_info = &op.u.physinfo;
-
- op.cmd = DOM0_PHYSINFO;
- op.interface_version = DOM0_INTERFACE_VERSION;
-
- if((ret = do_dom0_op(xc_handle, &op))) return ret;
-
- put_info->ht_per_core = got_info->ht_per_core;
- put_info->cores = got_info->cores;
- put_info->total_pages = got_info->total_pages;
- put_info->free_pages = got_info->free_pages;
- put_info->cpu_khz = got_info->cpu_khz;
-
- return 0;
-}
-
-
-int xc_sched_id(int xc_handle,
- int *sched_id)
-{
- int ret;
- dom0_op_t op;
-
- op.cmd = DOM0_SCHED_ID;
- op.interface_version = DOM0_INTERFACE_VERSION;
-
- if((ret = do_dom0_op(xc_handle, &op))) return ret;
-
- *sched_id = op.u.sched_id.sched_id;
-
- return 0;
-}
-
+++ /dev/null
-/******************************************************************************
- * xc_netbsd_build.c
- */
-
-#include "xc_private.h"
-#define ELFSIZE 32 /* XXX */
-#include "xc_elf.h"
-#include <zlib.h>
-
-#ifdef DEBUG
-#define DPRINTF(x) printf x
-#else
-#define DPRINTF(x)
-#endif
-
-static int loadelfimage(gzFile, int, unsigned long *, unsigned long,
- unsigned long *, unsigned long *,
- unsigned long *, unsigned long *);
-
-#define ELFROUND (ELFSIZE / 8)
-
-#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
-#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
-
-static long get_tot_pages(int xc_handle, u32 domid)
-{
- dom0_op_t op;
- op.cmd = DOM0_GETDOMAININFO;
- op.u.getdomaininfo.domain = (domid_t)domid;
- op.u.getdomaininfo.ctxt = NULL;
- return (do_dom0_op(xc_handle, &op) < 0) ?
- -1 : op.u.getdomaininfo.tot_pages;
-}
-
-static int get_pfn_list(int xc_handle,
- u32 domid,
- unsigned long *pfn_buf,
- unsigned long max_pfns)
-{
- dom0_op_t op;
- int ret;
- op.cmd = DOM0_GETMEMLIST;
- op.u.getmemlist.domain = (domid_t)domid;
- op.u.getmemlist.max_pfns = max_pfns;
- op.u.getmemlist.buffer = pfn_buf;
-
- if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
- return -1;
-
- ret = do_dom0_op(xc_handle, &op);
-
- (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
-
- return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
-}
-
-static int setup_guestos(int xc_handle,
- u32 dom,
- gzFile kernel_gfd,
- unsigned long tot_pages,
- unsigned long *virt_startinfo_addr,
- unsigned long *virt_load_addr,
- full_execution_context_t *ctxt,
- const char *cmdline,
- unsigned long shared_info_frame,
- unsigned int control_evtchn)
-{
- l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
- l2_pgentry_t *vl2tab=NULL, *vl2e=NULL;
- unsigned long *page_array = NULL;
- int alloc_index, num_pt_pages;
- unsigned long l2tab;
- unsigned long l1tab;
- unsigned long count, pt_start;
- unsigned long symtab_addr = 0, symtab_len = 0;
- extended_start_info_t *start_info;
- shared_info_t *shared_info;
- unsigned long ksize;
- mmu_t *mmu = NULL;
- int pm_handle, i;
-
- if ( (pm_handle = init_pfn_mapper((domid_t)dom)) < 0 )
- goto error_out;
-
- if ( (page_array = malloc(tot_pages * sizeof(unsigned long))) == NULL )
- {
- PERROR("Could not allocate memory");
- goto error_out;
- }
-
- if ( get_pfn_list(xc_handle, dom, page_array, tot_pages) != tot_pages )
- {
- PERROR("Could not get the page frame list");
- goto error_out;
- }
-
- if (loadelfimage(kernel_gfd, pm_handle, page_array, tot_pages,
- virt_load_addr, &ksize, &symtab_addr, &symtab_len))
- goto error_out;
-
- /* ksize is kernel-image size rounded up to a page boundary. */
-
- alloc_index = tot_pages - 1;
-
- /* Count bottom-level PTs, rounding up. */
- num_pt_pages = (l1_table_offset(*virt_load_addr) + tot_pages + 1023)
- / 1024;
-
- /* We must also count the page directory. */
- num_pt_pages++;
-
- /* Index of first PT page. */
- pt_start = tot_pages - num_pt_pages;
-
- /*
- * First allocate page for page dir. Allocation goes backwards from the end
- * of the allocated physical address space.
- */
- l2tab = page_array[alloc_index] << PAGE_SHIFT;
- alloc_index--;
- ctxt->pt_base = l2tab;
-
- if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL )
- goto error_out;
-
- /* Initialise the page tables. */
- if ( (vl2tab = map_pfn_writeable(pm_handle, l2tab >> PAGE_SHIFT)) == NULL )
- goto error_out;
- memset(vl2tab, 0, PAGE_SIZE);
- vl2e = &vl2tab[l2_table_offset(*virt_load_addr)];
- for ( count = 0; count < tot_pages; count++ )
- {
- if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
- {
- l1tab = page_array[alloc_index--] << PAGE_SHIFT;
- if ( vl1tab != NULL )
- unmap_pfn(pm_handle, vl1tab);
- if ( (vl1tab = map_pfn_writeable(pm_handle,
- l1tab >> PAGE_SHIFT)) == NULL )
- goto error_out;
- memset(vl1tab, 0, PAGE_SIZE);
- vl1e = &vl1tab[l1_table_offset(*virt_load_addr +
- (count<<PAGE_SHIFT))];
- *vl2e++ = l1tab | L2_PROT;
- }
-
- *vl1e = (page_array[count] << PAGE_SHIFT) | L1_PROT;
- if ( count >= pt_start )
- *vl1e &= ~_PAGE_RW;
- vl1e++;
-
- if ( add_mmu_update(xc_handle, mmu,
- (page_array[count] << PAGE_SHIFT) |
- MMU_MACHPHYS_UPDATE, count) )
- goto error_out;
- }
- unmap_pfn(pm_handle, vl1tab);
- unmap_pfn(pm_handle, vl2tab);
-
- /*
- * Pin down l2tab addr as page dir page - causes hypervisor to provide
- * correct protection for the page
- */
- if ( add_mmu_update(xc_handle, mmu,
- l2tab | MMU_EXTENDED_COMMAND, MMUEXT_PIN_L2_TABLE) )
- goto error_out;
-
- *virt_startinfo_addr =
- *virt_load_addr + ((alloc_index-1) << PAGE_SHIFT);
-
- start_info = map_pfn_writeable(pm_handle, page_array[alloc_index-1]);
- memset(start_info, 0, sizeof(*start_info));
- start_info->pt_base = *virt_load_addr + ((tot_pages-1) << PAGE_SHIFT);
- start_info->mod_start = symtab_addr;
- start_info->mod_len = symtab_len;
- start_info->nr_pages = tot_pages;
- start_info->shared_info = shared_info_frame << PAGE_SHIFT;
- start_info->flags = 0;
- start_info->domain_controller_evtchn = control_evtchn;
- strncpy(start_info->cmd_line, cmdline, MAX_CMDLINE);
- start_info->cmd_line[MAX_CMDLINE-1] = '\0';
- unmap_pfn(pm_handle, start_info);
-
- /* shared_info page starts its life empty. */
- shared_info = map_pfn_writeable(pm_handle, shared_info_frame);
- memset(shared_info, 0, PAGE_SIZE);
- /* Mask all upcalls... */
- for ( i = 0; i < MAX_VIRT_CPUS; i++ )
- shared_info->vcpu_data[i].evtchn_upcall_mask = 1;
- unmap_pfn(pm_handle, shared_info);
-
- /* Send the page update requests down to the hypervisor. */
- if ( finish_mmu_updates(xc_handle, mmu) )
- goto error_out;
-
- free(mmu);
- (void)close_pfn_mapper(pm_handle);
- free(page_array);
- return 0;
-
- error_out:
- if ( mmu != NULL )
- free(mmu);
- if ( pm_handle >= 0 )
- (void)close_pfn_mapper(pm_handle);
- if ( page_array == NULL )
- free(page_array);
- return -1;
-}
-
-int xc_netbsd_build(int xc_handle,
- u32 domid,
- const char *image_name,
- const char *cmdline,
- unsigned int control_evtchn)
-{
- dom0_op_t launch_op, op;
- unsigned long load_addr;
- long tot_pages;
- int kernel_fd = -1;
- gzFile kernel_gfd = NULL;
- int rc, i;
- full_execution_context_t st_ctxt, *ctxt = &st_ctxt;
- unsigned long virt_startinfo_addr;
-
- if ( (tot_pages = get_tot_pages(xc_handle, domid)) < 0 )
- {
- PERROR("Could not find total pages for domain");
- return 1;
- }
-
- kernel_fd = open(image_name, O_RDONLY);
- if ( kernel_fd < 0 )
- {
- PERROR("Could not open kernel image");
- return 1;
- }
-
- if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
- {
- PERROR("Could not allocate decompression state for state file");
- close(kernel_fd);
- return 1;
- }
-
- if ( mlock(&st_ctxt, sizeof(st_ctxt) ) )
- {
- PERROR("Unable to mlock ctxt");
- return 1;
- }
-
- op.cmd = DOM0_GETDOMAININFO;
- op.u.getdomaininfo.domain = (domid_t)domid;
- op.u.getdomaininfo.ctxt = ctxt;
- if ( (do_dom0_op(xc_handle, &op) < 0) ||
- ((u32)op.u.getdomaininfo.domain != domid) )
- {
- PERROR("Could not get info on domain");
- goto error_out;
- }
- if ( !(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED) ||
- (op.u.getdomaininfo.ctxt->pt_base != 0) )
- {
- ERROR("Domain is already constructed");
- goto error_out;
- }
-
- if ( setup_guestos(xc_handle, domid, kernel_gfd, tot_pages,
- &virt_startinfo_addr,
- &load_addr, &st_ctxt, cmdline,
- op.u.getdomaininfo.shared_info_frame,
- control_evtchn) < 0 )
- {
- ERROR("Error constructing guest OS");
- goto error_out;
- }
-
- if ( kernel_fd >= 0 )
- close(kernel_fd);
- if( kernel_gfd )
- gzclose(kernel_gfd);
-
- ctxt->flags = 0;
-
- /*
- * Initial register values:
- * DS,ES,FS,GS = FLAT_GUESTOS_DS
- * CS:EIP = FLAT_GUESTOS_CS:start_pc
- * SS:ESP = FLAT_GUESTOS_DS:start_stack
- * ESI = start_info
- * [EAX,EBX,ECX,EDX,EDI,EBP are zero]
- * EFLAGS = IF | 2 (bit 1 is reserved and should always be 1)
- */
- ctxt->cpu_ctxt.ds = FLAT_GUESTOS_DS;
- ctxt->cpu_ctxt.es = FLAT_GUESTOS_DS;
- ctxt->cpu_ctxt.fs = FLAT_GUESTOS_DS;
- ctxt->cpu_ctxt.gs = FLAT_GUESTOS_DS;
- ctxt->cpu_ctxt.ss = FLAT_GUESTOS_DS;
- ctxt->cpu_ctxt.cs = FLAT_GUESTOS_CS;
- ctxt->cpu_ctxt.eip = load_addr;
- ctxt->cpu_ctxt.esp = virt_startinfo_addr;
- ctxt->cpu_ctxt.esi = virt_startinfo_addr;
- ctxt->cpu_ctxt.eflags = (1<<9) | (1<<2);
-
- /* FPU is set up to default initial state. */
- memset(ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
-
- /* Virtual IDT is empty at start-of-day. */
- for ( i = 0; i < 256; i++ )
- {
- ctxt->trap_ctxt[i].vector = i;
- ctxt->trap_ctxt[i].cs = FLAT_GUESTOS_CS;
- }
- ctxt->fast_trap_idx = 0;
-
- /* No LDT. */
- ctxt->ldt_ents = 0;
-
- /* Use the default Xen-provided GDT. */
- ctxt->gdt_ents = 0;
-
- /* Ring 1 stack is the initial stack. */
- ctxt->guestos_ss = FLAT_GUESTOS_DS;
- ctxt->guestos_esp = virt_startinfo_addr;
-
- /* No debugging. */
- memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
-
- /* No callback handlers. */
- ctxt->event_callback_cs = FLAT_GUESTOS_CS;
- ctxt->event_callback_eip = 0;
- ctxt->failsafe_callback_cs = FLAT_GUESTOS_CS;
- ctxt->failsafe_callback_eip = 0;
-
- memset( &launch_op, 0, sizeof(launch_op) );
-
- launch_op.u.builddomain.domain = (domid_t)domid;
- launch_op.u.builddomain.ctxt = ctxt;
- launch_op.cmd = DOM0_BUILDDOMAIN;
- rc = do_dom0_op(xc_handle, &launch_op);
-
- return rc;
-
- error_out:
- if ( kernel_fd >= 0 )
- close(kernel_fd);
- if( kernel_gfd )
- gzclose(kernel_gfd);
-
- return -1;
-}
-
-#define MYSEEK_BUFSIZE 1024
-static off_t
-myseek(gzFile gfd, off_t offset, int whence)
-{
- unsigned char tmp[MYSEEK_BUFSIZE];
- int c;
-
- if ( offset < 0 )
- {
- ERROR("seek back not supported");
- return -1;
- }
-
- while ( offset != 0 )
- {
- c = offset;
- if ( c > MYSEEK_BUFSIZE )
- c = MYSEEK_BUFSIZE;
- if ( gzread(gfd, tmp, c) != c )
- {
- PERROR("Error seeking in image.");
- return -1;
- }
- offset -= c;
- }
-
- return 0; /* XXX */
-}
-
-/*
- * NetBSD memory layout:
- *
- * ---------------- *virt_load_addr = ehdr.e_entry (0xc0100000)
- * | kernel text |
- * | |
- * ----------------
- * | kernel data |
- * | |
- * ----------------
- * | kernel bss |
- * | |
- * ---------------- *symtab_addr
- * | symtab size | = *symtab_len
- * ----------------
- * | elf header | offsets to symbol sections mangled to be relative
- * | | to headers location
- * ----------------
- * | sym section |
- * | headers |
- * ----------------
- * | sym sections |
- * | |
- * ---------------- *symtab_addr + *symtab_len
- * | padding |
- * ---------------- ehdr.e_entry + *ksize << PAGE_SHIFT
- */
-
-#define IS_TEXT(p) (p.p_flags & PF_X)
-#define IS_DATA(p) (p.p_flags & PF_W)
-#define IS_BSS(p) (p.p_filesz < p.p_memsz)
-
-static int
-loadelfimage(gzFile kernel_gfd, int pm_handle, unsigned long *page_array,
- unsigned long tot_pages, unsigned long *virt_load_addr,
- unsigned long *ksize, unsigned long *symtab_addr,
- unsigned long *symtab_len)
-{
- Elf_Ehdr ehdr;
- Elf_Phdr *phdr;
- Elf_Shdr *shdr;
- void *vaddr;
- char page[PAGE_SIZE], *p;
- unsigned long iva, maxva, symva;
- int c, curpos, h, i, ret, s;
-
- ret = -1;
- phdr = NULL;
- p = NULL;
- maxva = 0;
-
- if ( gzread(kernel_gfd, &ehdr, sizeof(Elf_Ehdr)) != sizeof(Elf_Ehdr) )
- {
- PERROR("Error reading kernel image ELF header.");
- goto out;
- }
- curpos = sizeof(Elf_Ehdr);
-
- if ( !IS_ELF(ehdr) )
- {
- PERROR("Image does not have an ELF header.");
- goto out;
- }
-
- *virt_load_addr = ehdr.e_entry;
-
- if ( (*virt_load_addr & (PAGE_SIZE-1)) != 0 )
- {
- ERROR("We can only deal with page-aligned load addresses");
- goto out;
- }
-
- if ( (*virt_load_addr + (tot_pages << PAGE_SHIFT)) >
- HYPERVISOR_VIRT_START )
- {
- ERROR("Cannot map all domain memory without hitting Xen space");
- goto out;
- }
-
-
- phdr = malloc(ehdr.e_phnum * sizeof(Elf_Phdr));
- if ( phdr == NULL )
- {
- ERROR("Cannot allocate memory for Elf_Phdrs");
- goto out;
- }
-
- if ( myseek(kernel_gfd, ehdr.e_phoff - curpos, SEEK_SET) == -1 )
- {
- ERROR("Seek to program header failed");
- goto out;
- }
- curpos = ehdr.e_phoff;
-
- if ( gzread(kernel_gfd, phdr, ehdr.e_phnum * sizeof(Elf_Phdr)) !=
- ehdr.e_phnum * sizeof(Elf_Phdr) )
- {
- PERROR("Error reading kernel image ELF program header.");
- goto out;
- }
- curpos += ehdr.e_phnum * sizeof(Elf_Phdr);
-
- /* Copy run-time 'load' segments that are writeable and/or executable. */
- for ( h = 0; h < ehdr.e_phnum; h++ )
- {
- if ( (phdr[h].p_type != PT_LOAD) ||
- ((phdr[h].p_flags & (PF_W|PF_X)) == 0) )
- continue;
-
- if ( IS_TEXT(phdr[h]) || IS_DATA(phdr[h]) )
- {
- if ( myseek(kernel_gfd, phdr[h].p_offset - curpos,
- SEEK_SET) == -1 )
- {
- ERROR("Seek to section failed");
- goto out;
- }
- curpos = phdr[h].p_offset;
-
- for ( iva = phdr[h].p_vaddr;
- iva < phdr[h].p_vaddr + phdr[h].p_filesz;
- iva += c)
- {
- c = PAGE_SIZE - (iva & (PAGE_SIZE - 1));
- if (iva + c > phdr[h].p_vaddr + phdr[h].p_filesz)
- c = phdr[h].p_vaddr + phdr[h].p_filesz - iva;
- if ( gzread(kernel_gfd, page, c) != c )
- {
- PERROR("Error reading kernel image page.");
- goto out;
- }
- curpos += c;
- vaddr = map_pfn_writeable(pm_handle,
- page_array[(iva - *virt_load_addr)
- >> PAGE_SHIFT]);
- if ( vaddr == NULL )
- {
- ERROR("Couldn't map guest memory");
- goto out;
- }
- DPRINTF(("copy page %p to %p, count 0x%x\n", (void *)iva,
- vaddr + (iva & (PAGE_SIZE - 1)), c));
- memcpy(vaddr + (iva & (PAGE_SIZE - 1)), page, c);
- unmap_pfn(pm_handle, vaddr);
- }
-
- if ( phdr[h].p_vaddr + phdr[h].p_filesz > maxva )
- maxva = phdr[h].p_vaddr + phdr[h].p_filesz;
- }
-
- if ( IS_BSS(phdr[h]) )
- {
- /* XXX maybe clear phdr[h].p_memsz bytes from
- phdr[h].p_vaddr + phdr[h].p_filesz ??? */
- if (phdr[h].p_vaddr + phdr[h].p_memsz > maxva)
- maxva = phdr[h].p_vaddr + phdr[h].p_memsz;
- DPRINTF(("bss from %p to %p, maxva %p\n",
- (void *)(phdr[h].p_vaddr + phdr[h].p_filesz),
- (void *)(phdr[h].p_vaddr + phdr[h].p_memsz),
- (void *)maxva));
- }
- }
-
- p = malloc(sizeof(int) + sizeof(Elf_Ehdr) +
- ehdr.e_shnum * sizeof(Elf_Shdr));
- if ( p == NULL )
- {
- ERROR("Cannot allocate memory for Elf_Shdrs");
- goto out;
- }
-
- shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr));
-
- if ( myseek(kernel_gfd, ehdr.e_shoff - curpos, SEEK_SET) == -1 )
- {
- ERROR("Seek to symbol header failed");
- goto out;
- }
- curpos = ehdr.e_shoff;
-
- if ( gzread(kernel_gfd, shdr, ehdr.e_shnum * sizeof(Elf_Shdr)) !=
- ehdr.e_shnum * sizeof(Elf_Shdr) )
- {
- PERROR("Error reading kernel image ELF symbol header.");
- goto out;
- }
- curpos += ehdr.e_shnum * sizeof(Elf_Shdr);
-
- maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
- symva = maxva;
- maxva += sizeof(int);
- *symtab_addr = maxva;
- *symtab_len = 0;
- maxva += sizeof(Elf_Ehdr) + ehdr.e_shnum * sizeof(Elf_Shdr);
- maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
-
- /* Copy kernel string / symbol tables into physical memory */
- for ( h = 0; h < ehdr.e_shnum; h++ )
- {
- if ( shdr[h].sh_type == SHT_STRTAB )
- {
- /* Look for a strtab @i linked to symtab @h. */
- for ( i = 0; i < ehdr.e_shnum; i++ )
- if ( (shdr[i].sh_type == SHT_SYMTAB) &&
- (shdr[i].sh_link == h) )
- break;
- /* Skip symtab @h if we found no corresponding strtab @i. */
- if ( i == ehdr.e_shnum )
- {
- shdr[h].sh_offset = 0;
- continue;
- }
- }
-
- if ( (shdr[h].sh_type == SHT_STRTAB) ||
- (shdr[h].sh_type == SHT_SYMTAB) )
- {
- if ( myseek(kernel_gfd, shdr[h].sh_offset - curpos,
- SEEK_SET) == -1 )
- {
- ERROR("Seek to symbol section failed");
- goto out;
- }
- curpos = shdr[h].sh_offset;
-
- /* Mangled to be based on ELF header location. */
- shdr[h].sh_offset = maxva - *symtab_addr;
-
- DPRINTF(("copy section %d, size 0x%x\n", h, shdr[h].sh_size));
- for ( i = 0; i < shdr[h].sh_size; i += c, maxva += c )
- {
- c = PAGE_SIZE - (maxva & (PAGE_SIZE - 1));
- if ( c > (shdr[h].sh_size - i) )
- c = shdr[h].sh_size - i;
- if ( gzread(kernel_gfd, page, c) != c )
- {
- PERROR("Error reading kernel image page.");
- goto out;
- }
- curpos += c;
-
- vaddr = map_pfn_writeable(pm_handle,
- page_array[(maxva - *virt_load_addr)
- >> PAGE_SHIFT]);
- if ( vaddr == NULL )
- {
- ERROR("Couldn't map guest memory");
- goto out;
- }
- DPRINTF(("copy page %p to %p, count 0x%x\n", (void *)maxva,
- vaddr + (maxva & (PAGE_SIZE - 1)), c));
- memcpy(vaddr + (maxva & (PAGE_SIZE - 1)), page, c);
- unmap_pfn(pm_handle, vaddr);
- }
-
- *symtab_len += shdr[h].sh_size;
- maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
-
- }
- shdr[h].sh_name = 0; /* Name is NULL. */
- }
-
- if ( *symtab_len == 0 )
- {
- DPRINTF(("no symbol table\n"));
- *symtab_addr = 0;
- ret = 0;
- goto out;
- }
-
- DPRINTF(("sym header va %p from %p/%p size %x/%x\n", (void *)symva,
- shdr, p, ehdr.e_shnum * sizeof(Elf_Shdr),
- ehdr.e_shnum * sizeof(Elf_Shdr) + sizeof(Elf_Ehdr)));
- ehdr.e_phoff = 0;
- ehdr.e_shoff = sizeof(Elf_Ehdr);
- ehdr.e_phentsize = 0;
- ehdr.e_phnum = 0;
- ehdr.e_shstrndx = SHN_UNDEF;
- memcpy(p + sizeof(int), &ehdr, sizeof(Elf_Ehdr));
- *(int *)p = maxva - *symtab_addr;
-
- /* Copy total length, crafted ELF header and section header table */
- s = sizeof(int) + sizeof(Elf_Ehdr) + ehdr.e_shnum * sizeof(Elf_Shdr);
- for ( i = 0; i < s; i += c, symva += c )
- {
- c = PAGE_SIZE - (symva & (PAGE_SIZE - 1));
- if ( c > s - i )
- c = s - i;
- vaddr = map_pfn_writeable(pm_handle,
- page_array[(symva - *virt_load_addr)
- >> PAGE_SHIFT]);
- if ( vaddr == NULL )
- {
- ERROR("Couldn't map guest memory");
- goto out;
- }
- DPRINTF(("copy page %p to %p, count 0x%x\n", (void *)symva,
- vaddr + (symva & (PAGE_SIZE - 1)), c));
- memcpy(vaddr + (symva & (PAGE_SIZE - 1)), p + i,
- c);
- unmap_pfn(pm_handle, vaddr);
- }
-
- *symtab_len = maxva - *symtab_addr;
-
- ret = 0;
-
- out:
- if ( ret == 0 )
- {
- maxva = (maxva + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
- *ksize = (maxva - *virt_load_addr) >> PAGE_SHIFT;
-
- DPRINTF(("virt_addr %p, kpages 0x%lx, symtab_addr %p, symtab_len %p\n",
- (void *)*virt_load_addr, *ksize, (void *)*symtab_addr,
- (void *)*symtab_len));
- }
-
- if ( phdr != NULL )
- free(phdr);
- if ( p != NULL )
- free(p);
- return ret;
-}
+++ /dev/null
-/******************************************************************************
- * xc_physdev.c
- *
- * API for manipulating physical-device access permissions.
- *
- * Copyright (c) 2004, Rolf Neugebauer (Intel Research Cambridge)
- * Copyright (c) 2004, K A Fraser (University of Cambridge)
- */
-
-#include "xc_private.h"
-
-int xc_physdev_pci_access_modify(int xc_handle,
- u32 domid,
- int bus,
- int dev,
- int func,
- int enable)
-{
- dom0_op_t op;
-
- op.cmd = DOM0_PCIDEV_ACCESS;
- op.u.pcidev_access.domain = (domid_t)domid;
- op.u.pcidev_access.bus = bus;
- op.u.pcidev_access.dev = dev;
- op.u.pcidev_access.func = func;
- op.u.pcidev_access.enable = enable;
-
- return do_dom0_op(xc_handle, &op);
-}
+++ /dev/null
-/******************************************************************************
- * xc_private.c
- *
- * Helper functions for the rest of the library.
- */
-
-#include "xc_private.h"
-
-int init_pfn_mapper(domid_t domid)
-{
- int fd = open("/dev/mem", O_RDWR);
- if ( fd >= 0 )
- (void)ioctl(fd, _IO('M', 1), (unsigned long)domid);
- return fd;
-}
-
-int close_pfn_mapper(int pm_handle)
-{
- return close(pm_handle);
-}
-
-void *map_pfn_writeable(int pm_handle, unsigned long pfn)
-{
- void *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE,
- MAP_SHARED, pm_handle, pfn << PAGE_SHIFT);
- if ( vaddr == MAP_FAILED )
- return NULL;
- return vaddr;
-}
-
-void *map_pfn_readonly(int pm_handle, unsigned long pfn)
-{
- void *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ,
- MAP_SHARED, pm_handle, pfn << PAGE_SHIFT);
- if ( vaddr == MAP_FAILED )
- return NULL;
- return vaddr;
-}
-
-void unmap_pfn(int pm_handle, void *vaddr)
-{
- (void)munmap(vaddr, PAGE_SIZE);
-}
-
-/*******************/
-
-void * mfn_mapper_map_batch(int xc_handle, domid_t dom, int prot,
- unsigned long *arr, int num )
-{
- privcmd_mmapbatch_t ioctlx;
- void *addr;
- addr = mmap( NULL, num*PAGE_SIZE, prot, MAP_SHARED, xc_handle, 0 );
- if (addr)
- {
- ioctlx.num=num;
- ioctlx.dom=dom;
- ioctlx.addr=(unsigned long)addr;
- ioctlx.arr=arr;
- if ( ioctl( xc_handle, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx ) < 0 )
- {
- perror("XXXXXXXX");
- munmap(addr, num*PAGE_SIZE);
- return 0;
- }
- }
- return addr;
-
-}
-
-/*******************/
-
-void * mfn_mapper_map_single(int xc_handle, domid_t dom,
- int size, int prot,
- unsigned long mfn )
-{
- privcmd_mmap_t ioctlx;
- privcmd_mmap_entry_t entry;
- void *addr;
- addr = mmap( NULL, size, prot, MAP_SHARED, xc_handle, 0 );
- if (addr)
- {
- ioctlx.num=1;
- ioctlx.dom=dom;
- ioctlx.entry=&entry;
- entry.va=(unsigned long) addr;
- entry.mfn=mfn;
- entry.npages=(size+PAGE_SIZE-1)>>PAGE_SHIFT;
- if ( ioctl( xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx ) <0 )
- {
- munmap(addr, size);
- return 0;
- }
- }
- return addr;
-}
-
-/*******************/
-
-/* NB: arr must be mlock'ed */
-int get_pfn_type_batch(int xc_handle,
- u32 dom, int num, unsigned long *arr)
-{
- dom0_op_t op;
- op.cmd = DOM0_GETPAGEFRAMEINFO2;
- op.u.getpageframeinfo2.domain = (domid_t)dom;
- op.u.getpageframeinfo2.num = num;
- op.u.getpageframeinfo2.array = arr;
- return do_dom0_op(xc_handle, &op);
-}
-
-#define GETPFN_ERR (~0U)
-unsigned int get_pfn_type(int xc_handle,
- unsigned long mfn,
- u32 dom)
-{
- dom0_op_t op;
- op.cmd = DOM0_GETPAGEFRAMEINFO;
- op.u.getpageframeinfo.pfn = mfn;
- op.u.getpageframeinfo.domain = (domid_t)dom;
- if ( do_dom0_op(xc_handle, &op) < 0 )
- {
- PERROR("Unexpected failure when getting page frame info!");
- return GETPFN_ERR;
- }
- return op.u.getpageframeinfo.type;
-}
-
-
-
-/*******************/
-
-#define FIRST_MMU_UPDATE 1
-
-static int flush_mmu_updates(int xc_handle, mmu_t *mmu)
-{
- int err = 0;
- privcmd_hypercall_t hypercall;
-
- if ( mmu->idx == FIRST_MMU_UPDATE )
- return 0;
-
- /* The first two requests set the correct subject domain (PTS and GPS). */
- mmu->updates[0].val = (unsigned long)(mmu->subject<<16) & ~0xFFFFUL;
- mmu->updates[0].ptr = (unsigned long)(mmu->subject<< 0) & ~0xFFFFUL;
- mmu->updates[0].ptr |= MMU_EXTENDED_COMMAND;
- mmu->updates[0].val |= MMUEXT_SET_SUBJECTDOM | SET_PAGETABLE_SUBJECTDOM;
-
- hypercall.op = __HYPERVISOR_mmu_update;
- hypercall.arg[0] = (unsigned long)mmu->updates;
- hypercall.arg[1] = (unsigned long)mmu->idx;
- hypercall.arg[2] = 0;
-
- if ( mlock(mmu->updates, sizeof(mmu->updates)) != 0 )
- {
- PERROR("Could not lock pagetable update array");
- err = 1;
- goto out;
- }
-
- if ( do_xen_hypercall(xc_handle, &hypercall) < 0 )
- {
- ERROR("Failure when submitting mmu updates");
- err = 1;
- }
-
- mmu->idx = FIRST_MMU_UPDATE;
-
- (void)munlock(mmu->updates, sizeof(mmu->updates));
-
- out:
- return err;
-}
-
-mmu_t *init_mmu_updates(int xc_handle, domid_t dom)
-{
- mmu_t *mmu = malloc(sizeof(mmu_t));
- if ( mmu == NULL )
- return mmu;
- mmu->idx = FIRST_MMU_UPDATE;
- mmu->subject = dom;
- return mmu;
-}
-
-int add_mmu_update(int xc_handle, mmu_t *mmu,
- unsigned long ptr, unsigned long val)
-{
- mmu->updates[mmu->idx].ptr = ptr;
- mmu->updates[mmu->idx].val = val;
-
- if ( ++mmu->idx == MAX_MMU_UPDATES )
- return flush_mmu_updates(xc_handle, mmu);
-
- return 0;
-}
-
-int finish_mmu_updates(int xc_handle, mmu_t *mmu)
-{
- return flush_mmu_updates(xc_handle, mmu);
-}
-
-
-long long xc_domain_get_cpu_usage( int xc_handle, domid_t domid )
-{
- dom0_op_t op;
-
- op.cmd = DOM0_GETDOMAININFO;
- op.u.getdomaininfo.domain = (domid_t)domid;
- op.u.getdomaininfo.ctxt = NULL;
- if ( (do_dom0_op(xc_handle, &op) < 0) ||
- ((u32)op.u.getdomaininfo.domain != domid) )
- {
- PERROR("Could not get info on domain");
- return -1;
- }
- return op.u.getdomaininfo.cpu_time;
-}
-
-
-/* This is shared between save and restore, and may generally be useful. */
-unsigned long csum_page (void * page)
-{
- int i;
- unsigned long *p = page;
- unsigned long long sum=0;
-
- for ( i = 0; i < (PAGE_SIZE/sizeof(unsigned long)); i++ )
- sum += p[i];
-
- return sum ^ (sum>>32);
-}
+++ /dev/null
-
-#ifndef __XC_PRIVATE_H__
-#define __XC_PRIVATE_H__
-
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <string.h>
-
-#include "xc.h"
-
-/* from xen/include/hypervisor-ifs */
-#include <hypervisor-if.h>
-#include <dom0_ops.h>
-#include <event_channel.h>
-#include <sched_ctl.h>
-
-#include <asm-xen/proc_cmd.h>
-
-/* from xend/lib */
-#include <domain_controller.h>
-
-#define _PAGE_PRESENT 0x001
-#define _PAGE_RW 0x002
-#define _PAGE_USER 0x004
-#define _PAGE_PWT 0x008
-#define _PAGE_PCD 0x010
-#define _PAGE_ACCESSED 0x020
-#define _PAGE_DIRTY 0x040
-#define _PAGE_PAT 0x080
-#define _PAGE_PSE 0x080
-#define _PAGE_GLOBAL 0x100
-
-
-#define L1_PAGETABLE_SHIFT 12
-#define L2_PAGETABLE_SHIFT 22
-
-#define ENTRIES_PER_L1_PAGETABLE 1024
-#define ENTRIES_PER_L2_PAGETABLE 1024
-
-#define PAGE_SHIFT L1_PAGETABLE_SHIFT
-#define PAGE_SIZE (1UL << PAGE_SHIFT)
-#define PAGE_MASK (~(PAGE_SIZE-1))
-
-typedef unsigned long l1_pgentry_t;
-typedef unsigned long l2_pgentry_t;
-
-#define l1_table_offset(_a) \
- (((_a) >> L1_PAGETABLE_SHIFT) & (ENTRIES_PER_L1_PAGETABLE - 1))
-#define l2_table_offset(_a) \
- ((_a) >> L2_PAGETABLE_SHIFT)
-
-#define ERROR(_m, _a...) \
- fprintf(stderr, "ERROR: " _m "\n" , ## _a )
-
-#define PERROR(_m, _a...) \
- fprintf(stderr, "ERROR: " _m " (%d = %s)\n" , ## _a , \
- errno, strerror(errno))
-
-static inline int do_privcmd(int xc_handle,
- unsigned int cmd,
- unsigned long data)
-{
- return ioctl(xc_handle, cmd, data);
-}
-
-static inline int do_xen_hypercall(int xc_handle,
- privcmd_hypercall_t *hypercall)
-{
- return do_privcmd(xc_handle,
- IOCTL_PRIVCMD_HYPERCALL,
- (unsigned long)hypercall);
-}
-
-static inline int do_dom0_op(int xc_handle, dom0_op_t *op)
-{
- int ret = -1;
- privcmd_hypercall_t hypercall;
-
- op->interface_version = DOM0_INTERFACE_VERSION;
-
- hypercall.op = __HYPERVISOR_dom0_op;
- hypercall.arg[0] = (unsigned long)op;
-
- if ( mlock(op, sizeof(*op)) != 0 )
- {
- PERROR("Could not lock memory for Xen hypercall");
- goto out1;
- }
-
- if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
- {
- if ( errno == EACCES )
- fprintf(stderr, "Dom0 operation failed -- need to"
- " rebuild the user-space tool set?\n");
- goto out2;
- }
-
- out2: (void)munlock(op, sizeof(*op));
- out1: return ret;
-}
-
-static inline int do_multicall_op(int xc_handle,
- void *call_list, int nr_calls)
-{
- int ret = -1;
- privcmd_hypercall_t hypercall;
-
- hypercall.op = __HYPERVISOR_multicall;
- hypercall.arg[0] = (unsigned long)call_list;
- hypercall.arg[1] = (unsigned long)nr_calls;
-
- if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
- {
- if ( errno == EACCES )
- fprintf(stderr, "Dom0 operation failed -- need to"
- " rebuild the user-space tool set?\n");
- goto out1;
- }
-
- out1: return ret;
-}
-
-/*
- * PFN mapping.
- */
-int init_pfn_mapper(domid_t domid);
-int close_pfn_mapper(int pm_handle);
-void *map_pfn_writeable(int pm_handle, unsigned long pfn);
-void *map_pfn_readonly(int pm_handle, unsigned long pfn);
-void unmap_pfn(int pm_handle, void *vaddr);
-int get_pfn_type_batch(int xc_handle, u32 dom, int num, unsigned long *arr);
-unsigned long csum_page (void * page);
-
-/*
- * MMU updates.
- */
-#define MAX_MMU_UPDATES 1024
-typedef struct {
- mmu_update_t updates[MAX_MMU_UPDATES];
- int idx;
- domid_t subject;
-} mmu_t;
-mmu_t *init_mmu_updates(int xc_handle, domid_t dom);
-int add_mmu_update(int xc_handle, mmu_t *mmu,
- unsigned long ptr, unsigned long val);
-int finish_mmu_updates(int xc_handle, mmu_t *mmu);
-
-
-/*
- * ioctl-based mfn mapping interface
- */
-
-/*
-typedef struct privcmd_mmap_entry {
- unsigned long va;
- unsigned long mfn;
- unsigned long npages;
-} privcmd_mmap_entry_t;
-
-typedef struct privcmd_mmap {
- int num;
- domid_t dom;
- privcmd_mmap_entry_t *entry;
-} privcmd_mmap_t;
-*/
-
-#define mfn_mapper_queue_size 128
-
-typedef struct mfn_mapper {
- int xc_handle;
- int size;
- int prot;
- int error;
- int max_queue_size;
- void * addr;
- privcmd_mmap_t ioctl;
-
-} mfn_mapper_t;
-
-void * mfn_mapper_map_single(int xc_handle, domid_t dom, int size, int prot,
- unsigned long mfn );
-
-void * mfn_mapper_map_batch(int xc_handle, domid_t dom, int prot,
- unsigned long *arr, int num );
-
-mfn_mapper_t * mfn_mapper_init(int xc_handle, domid_t dom, int size, int prot);
-
-void * mfn_mapper_base(mfn_mapper_t *t);
-
-void mfn_mapper_close(mfn_mapper_t *t);
-
-int mfn_mapper_flush_queue(mfn_mapper_t *t);
-
-void * mfn_mapper_queue_entry(mfn_mapper_t *t, int offset,
- unsigned long mfn, int size );
-
-long long xc_domain_get_cpu_usage( int xc_handle, domid_t domid );
-
-#include "xc_io.h"
-
-int xc_domain_getfullinfo(int xc_handle,
- u32 domid,
- dom0_op_t *op,
- full_execution_context_t *ctxt );
-#endif /* __XC_PRIVATE_H__ */
+++ /dev/null
-/******************************************************************************
- * xc_rrobin.c
- *
- * API for manipulating parameters of the Round Robin scheduler
- *
- * by Mark Williamson, Copyright (c) 2004 Intel Research Cambridge.
- */
-
-#include "xc_private.h"
-
-int xc_rrobin_global_set(int xc_handle, u64 slice)
-{
- dom0_op_t op;
- op.cmd = DOM0_SCHEDCTL;
- op.u.schedctl.sched_id = SCHED_RROBIN;
- op.u.schedctl.direction = SCHED_INFO_PUT;
-
- op.u.schedctl.u.rrobin.slice = slice;
- return do_dom0_op(xc_handle, &op);
-}
-
-
-int xc_rrobin_global_get(int xc_handle, u64 *slice)
-{
- dom0_op_t op;
- int ret;
-
- op.cmd = DOM0_SCHEDCTL;
- op.u.schedctl.sched_id = SCHED_RROBIN;
- op.u.schedctl.direction = SCHED_INFO_GET;
-
- ret = do_dom0_op(xc_handle, &op);
-
- *slice = op.u.schedctl.u.rrobin.slice;
-
- return ret;
-}
+++ /dev/null
-
-all:
- python setup.py build
-
-install: all
- if [ "$(prefix)" = "" ]; then \
- python setup.py install; \
- elif [ "$(dist)" = "yes" ]; then \
- python setup.py install --home="$(prefix)"; \
- else \
- python setup.py install --root="$(prefix)"; \
- fi
-
-clean:
- rm -rf build *.pyc *.pyo *.o *.a *~
+++ /dev/null
-/******************************************************************************
- * Xc.c
- *
- * Copyright (c) 2003-2004, K A Fraser (University of Cambridge)
- */
-
-#include <Python.h>
-#include <xc.h>
-#include <zlib.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include "xc_private.h"
-#include "gzip_stream.h"
-
-/* Needed for Python versions earlier than 2.3. */
-#ifndef PyMODINIT_FUNC
-#define PyMODINIT_FUNC DL_EXPORT(void)
-#endif
-
-#define XENPKG "xen.ext.xc"
-
-static PyObject *xc_error, *zero;
-
-typedef struct {
- PyObject_HEAD;
- int xc_handle;
-} XcObject;
-
-/*
- * Definitions for the 'xc' object type.
- */
-
-static PyObject *pyxc_domain_create(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- unsigned int mem_kb = 0;
- char *name = "(anon)";
- int cpu = -1;
- u32 dom;
- int ret;
-
- static char *kwd_list[] = { "mem_kb", "name", "cpu", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|isi", kwd_list,
- &mem_kb, &name, &cpu) )
- return NULL;
-
- if ( (ret = xc_domain_create(xc->xc_handle, mem_kb, name, cpu, &dom)) < 0 )
- return PyErr_SetFromErrno(xc_error);
-
- return PyInt_FromLong(dom);
-}
-
-static PyObject *pyxc_domain_pause(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- u32 dom;
-
- static char *kwd_list[] = { "dom", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) )
- return NULL;
-
- if ( xc_domain_pause(xc->xc_handle, dom) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-static PyObject *pyxc_domain_unpause(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- u32 dom;
-
- static char *kwd_list[] = { "dom", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) )
- return NULL;
-
- if ( xc_domain_unpause(xc->xc_handle, dom) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-static PyObject *pyxc_domain_destroy(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- u32 dom;
-
- static char *kwd_list[] = { "dom", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) )
- return NULL;
-
- if ( xc_domain_destroy(xc->xc_handle, dom) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-static PyObject *pyxc_domain_pincpu(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- u32 dom;
- int cpu = -1;
-
- static char *kwd_list[] = { "dom", "cpu", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
- &dom, &cpu) )
- return NULL;
-
- if ( xc_domain_pincpu(xc->xc_handle, dom, cpu) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-static PyObject *pyxc_domain_getinfo(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
- PyObject *list;
-
- u32 first_dom = 0;
- int max_doms = 1024, nr_doms, i;
- xc_dominfo_t *info;
-
- static char *kwd_list[] = { "first_dom", "max_doms", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list,
- &first_dom, &max_doms) )
- return NULL;
-
- if ( (info = malloc(max_doms * sizeof(xc_dominfo_t))) == NULL )
- return PyErr_NoMemory();
-
- nr_doms = xc_domain_getinfo(xc->xc_handle, first_dom, max_doms, info);
-
- list = PyList_New(nr_doms);
- for ( i = 0 ; i < nr_doms; i++ )
- {
- PyList_SetItem(
- list, i,
- Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i"
- ",s:l,s:L,s:s,s:l,s:i}",
- "dom", info[i].domid,
- "cpu", info[i].cpu,
- "dying", info[i].dying,
- "crashed", info[i].crashed,
- "shutdown", info[i].shutdown,
- "paused", info[i].paused,
- "blocked", info[i].blocked,
- "running", info[i].running,
- "mem_kb", info[i].nr_pages*4,
- "cpu_time", info[i].cpu_time,
- "name", info[i].name,
- "maxmem_kb", info[i].max_memkb,
- "shutdown_reason", info[i].shutdown_reason
- ));
- }
-
- free(info);
-
- return list;
-}
-
-static int file_save(XcObject *xc, XcIOContext *ctxt, char *state_file){
- int rc = -1;
- int fd = -1;
- int open_flags = (O_CREAT | O_EXCL | O_WRONLY);
- int open_mode = 0644;
-
- printf("%s>\n", __FUNCTION__);
- fd = open(state_file, open_flags, open_mode);
- if(fd < 0){
- xcio_perror(ctxt, "Could not open file for writing");
- goto exit;
- }
- /* Compression rate 1: we want speed over compression.
- * We're mainly going for those zero pages, after all.
- */
- printf("%s>gzip_stream_fdopen... \n", __FUNCTION__);
- ctxt->io = gzip_stream_fdopen(fd, "wb1");
- if(!ctxt->io){
- xcio_perror(ctxt, "Could not allocate compression state");
- goto exit;
- }
- printf("%s> xc_linux_save...\n", __FUNCTION__);
- rc = xc_linux_save(xc->xc_handle, ctxt);
- exit:
- if(ctxt->io) IOStream_close(ctxt->io);
- if(fd >= 0) close(fd);
- unlink(state_file);
- printf("%s> rc=%d\n", __FUNCTION__, rc);
- return rc;
-}
-
-static PyObject *pyxc_linux_save(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- u32 dom;
- char *state_file;
- int progress = 1, debug = 0;
- unsigned int flags = 0;
- PyObject *val = NULL;
- int rc = -1;
- XcIOContext ioctxt = { .info = iostdout, .err = iostderr };
-
- static char *kwd_list[] = { "dom", "state_file", "vmconfig", "progress", "debug", NULL };
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "is|sii", kwd_list,
- &ioctxt.domain,
- &state_file,
- &ioctxt.vmconfig,
- &progress,
- &debug)){
- goto exit;
- }
- ioctxt.vmconfig_n = (ioctxt.vmconfig ? strlen(ioctxt.vmconfig) : 0);
- if (progress) ioctxt.flags |= XCFLAGS_VERBOSE;
- if (debug) ioctxt.flags |= XCFLAGS_DEBUG;
- if(!state_file || state_file[0] == '\0') goto exit;
- rc = file_save(xc, &ioctxt, state_file);
- if(rc){
- PyErr_SetFromErrno(xc_error);
- goto exit;
- }
- //xc_domain_destroy(xc->xc_handle, dom);
- Py_INCREF(zero);
- val = zero;
- exit:
- return val;
-}
-
-
-static int file_restore(XcObject *xc, XcIOContext *ioctxt, char *state_file){
- int rc = -1;
-
- ioctxt->io = gzip_stream_fopen(state_file, "rb");
- if (!ioctxt->io) {
- xcio_perror(ioctxt, "Could not open file for reading");
- goto exit;
- }
-
- rc = xc_linux_restore(xc->xc_handle, ioctxt);
- exit:
- if(ioctxt->io) IOStream_close(ioctxt->io);
- return rc;
-}
-
-static PyObject *pyxc_linux_restore(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
- char *state_file;
- int progress = 1, debug = 0;
- u32 dom;
- PyObject *val = NULL;
- XcIOContext ioctxt = { .info = iostdout, .err = iostderr };
- int rc =-1;
-
- static char *kwd_list[] = { "state_file", "progress", "debug", NULL };
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "is|ii", kwd_list,
- &ioctxt.domain,
- &state_file,
- &progress,
- &debug)){
- goto exit;
- }
- if (progress) ioctxt.flags |= XCFLAGS_VERBOSE;
- if (debug) ioctxt.flags |= XCFLAGS_DEBUG;
-
- if(!state_file || state_file[0] == '\0') goto exit;
- rc = file_restore(xc, &ioctxt, state_file);
- if(rc){
- PyErr_SetFromErrno(xc_error);
- goto exit;
- }
- val = Py_BuildValue("{s:i,s:s}",
- "dom", ioctxt.domain,
- "vmconfig", ioctxt.vmconfig);
- //? free(ioctxt.vmconfig);
- exit:
- return val;
-}
-
-static PyObject *pyxc_linux_build(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- u32 dom;
- char *image, *ramdisk = NULL, *cmdline = "";
- int control_evtchn, flags = 0;
-
- static char *kwd_list[] = { "dom", "control_evtchn",
- "image", "ramdisk", "cmdline", "flags",
- NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssi", kwd_list,
- &dom, &control_evtchn,
- &image, &ramdisk, &cmdline, &flags) )
- return NULL;
-
- if ( xc_linux_build(xc->xc_handle, dom, image,
- ramdisk, cmdline, control_evtchn, flags) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-static PyObject *pyxc_netbsd_build(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- u32 dom;
- char *image, *ramdisk = NULL, *cmdline = "";
- int control_evtchn;
-
- static char *kwd_list[] = { "dom", "control_evtchn",
- "image", "ramdisk", "cmdline", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssi", kwd_list,
- &dom, &control_evtchn,
- &image, &ramdisk, &cmdline) )
- return NULL;
-
- if ( xc_netbsd_build(xc->xc_handle, dom, image,
- cmdline, control_evtchn) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-static PyObject *pyxc_bvtsched_global_set(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- unsigned long ctx_allow;
-
- static char *kwd_list[] = { "ctx_allow", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "l", kwd_list, &ctx_allow) )
- return NULL;
-
- if ( xc_bvtsched_global_set(xc->xc_handle, ctx_allow) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-static PyObject *pyxc_bvtsched_global_get(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- unsigned long ctx_allow;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- if ( xc_bvtsched_global_get(xc->xc_handle, &ctx_allow) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- return Py_BuildValue("s:l", "ctx_allow", ctx_allow);
-}
-
-static PyObject *pyxc_bvtsched_domain_set(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- u32 dom;
- unsigned long mcuadv, warp, warpl, warpu;
-
- static char *kwd_list[] = { "dom", "mcuadv", "warp", "warpl",
- "warpu", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "illll", kwd_list,
- &dom, &mcuadv, &warp, &warpl, &warpu) )
- return NULL;
-
- if ( xc_bvtsched_domain_set(xc->xc_handle, dom, mcuadv,
- warp, warpl, warpu) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-static PyObject *pyxc_bvtsched_domain_get(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
- u32 dom;
- unsigned long mcuadv, warp, warpl, warpu;
-
- static char *kwd_list[] = { "dom", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) )
- return NULL;
-
- if ( xc_bvtsched_domain_get(xc->xc_handle, dom, &mcuadv, &warp,
- &warpl, &warpu) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- return Py_BuildValue("{s:i,s:l,s:l,s:l,s:l}",
- "domain", dom,
- "mcuadv", mcuadv,
- "warp", warp,
- "warpl", warpl,
- "warpu", warpu);
-}
-
-static PyObject *pyxc_evtchn_bind_interdomain(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- u32 dom1 = DOMID_SELF, dom2 = DOMID_SELF;
- int port1, port2;
-
- static char *kwd_list[] = { "dom1", "dom2", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list,
- &dom1, &dom2) )
- return NULL;
-
- if ( xc_evtchn_bind_interdomain(xc->xc_handle, dom1,
- dom2, &port1, &port2) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- return Py_BuildValue("{s:i,s:i}",
- "port1", port1,
- "port2", port2);
-}
-
-static PyObject *pyxc_evtchn_bind_virq(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- int virq, port;
-
- static char *kwd_list[] = { "virq", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &virq) )
- return NULL;
-
- if ( xc_evtchn_bind_virq(xc->xc_handle, virq, &port) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- return PyInt_FromLong(port);
-}
-
-static PyObject *pyxc_evtchn_close(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- u32 dom = DOMID_SELF;
- int port;
-
- static char *kwd_list[] = { "port", "dom", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
- &port, &dom) )
- return NULL;
-
- if ( xc_evtchn_close(xc->xc_handle, dom, port) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-static PyObject *pyxc_evtchn_send(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- int port;
-
- static char *kwd_list[] = { "port", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &port) )
- return NULL;
-
- if ( xc_evtchn_send(xc->xc_handle, port) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-static PyObject *pyxc_evtchn_status(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
- PyObject *dict;
-
- u32 dom = DOMID_SELF;
- int port, ret;
- xc_evtchn_status_t status;
-
- static char *kwd_list[] = { "port", "dom", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
- &port, &dom) )
- return NULL;
-
- ret = xc_evtchn_status(xc->xc_handle, dom, port, &status);
- if ( ret != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- switch ( status.status )
- {
- case EVTCHNSTAT_closed:
- dict = Py_BuildValue("{s:s}",
- "status", "closed");
- break;
- case EVTCHNSTAT_unbound:
- dict = Py_BuildValue("{s:s}",
- "status", "unbound");
- break;
- case EVTCHNSTAT_interdomain:
- dict = Py_BuildValue("{s:s,s:i,s:i}",
- "status", "interdomain",
- "dom", status.u.interdomain.dom,
- "port", status.u.interdomain.port);
- break;
- case EVTCHNSTAT_pirq:
- dict = Py_BuildValue("{s:s,s:i}",
- "status", "pirq",
- "irq", status.u.pirq);
- break;
- case EVTCHNSTAT_virq:
- dict = Py_BuildValue("{s:s,s:i}",
- "status", "virq",
- "irq", status.u.virq);
- break;
- default:
- dict = Py_BuildValue("{}");
- break;
- }
-
- return dict;
-}
-
-static PyObject *pyxc_physdev_pci_access_modify(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
- u32 dom;
- int bus, dev, func, enable, ret;
-
- static char *kwd_list[] = { "dom", "bus", "dev", "func", "enable", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiii", kwd_list,
- &dom, &bus, &dev, &func, &enable) )
- return NULL;
-
- ret = xc_physdev_pci_access_modify(
- xc->xc_handle, dom, bus, dev, func, enable);
- if ( ret != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-static PyObject *pyxc_readconsolering(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- unsigned int clear = 0;
- char str[32768];
- int ret;
-
- static char *kwd_list[] = { "clear", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &clear) )
- return NULL;
-
- ret = xc_readconsolering(xc->xc_handle, str, sizeof(str), clear);
- if ( ret < 0 )
- return PyErr_SetFromErrno(xc_error);
-
- return PyString_FromStringAndSize(str, ret);
-}
-
-static PyObject *pyxc_physinfo(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
- xc_physinfo_t info;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- if ( xc_physinfo(xc->xc_handle, &info) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- return Py_BuildValue("{s:i,s:i,s:l,s:l,s:l}",
- "ht_per_core", info.ht_per_core,
- "cores", info.cores,
- "total_pages", info.total_pages,
- "free_pages", info.free_pages,
- "cpu_khz", info.cpu_khz);
-}
-
-static PyObject *pyxc_atropos_domain_set(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
- u32 domid;
- u64 period, slice, latency;
- int xtratime;
-
- static char *kwd_list[] = { "dom", "period", "slice", "latency",
- "xtratime", NULL };
-
- if( !PyArg_ParseTupleAndKeywords(args, kwds, "iLLLi", kwd_list, &domid,
- &period, &slice, &latency, &xtratime) )
- return NULL;
-
- if ( xc_atropos_domain_set(xc->xc_handle, domid, period, slice,
- latency, xtratime) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-static PyObject *pyxc_atropos_domain_get(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
- u32 domid;
- u64 period, slice, latency;
- int xtratime;
-
- static char *kwd_list[] = { "dom", NULL };
-
- if( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &domid) )
- return NULL;
-
- if ( xc_atropos_domain_get( xc->xc_handle, domid, &period,
- &slice, &latency, &xtratime ) )
- return PyErr_SetFromErrno(xc_error);
-
- return Py_BuildValue("{s:i,s:L,s:L,s:L,s:i}",
- "domain", domid,
- "period", period,
- "slice", slice,
- "latency", latency,
- "xtratime", xtratime);
-}
-
-
-static PyObject *pyxc_rrobin_global_set(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
- u64 slice;
-
- static char *kwd_list[] = { "slice", NULL };
-
- if( !PyArg_ParseTupleAndKeywords(args, kwds, "L", kwd_list, &slice) )
- return NULL;
-
- if ( xc_rrobin_global_set(xc->xc_handle, slice) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-static PyObject *pyxc_shadow_control(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- u32 dom;
- int op=0;
-
- static char *kwd_list[] = { "dom", "op", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
- &dom, &op) )
- return NULL;
-
- if ( xc_shadow_control(xc->xc_handle, dom, op, NULL, 0, NULL) < 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-static PyObject *pyxc_rrobin_global_get(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
- u64 slice;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- if ( xc_rrobin_global_get(xc->xc_handle, &slice) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- return Py_BuildValue("{s:L}", "slice", slice);
-}
-
-static PyObject *pyxc_domain_setname(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
- u32 dom;
- char *name;
-
- static char *kwd_list[] = { "dom", "name", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is", kwd_list,
- &dom, &name) )
- return NULL;
-
- if ( xc_domain_setname(xc->xc_handle, dom, name) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-static PyObject *pyxc_domain_setmaxmem(PyObject *self,
- PyObject *args,
- PyObject *kwds)
-{
- XcObject *xc = (XcObject *)self;
-
- u32 dom;
- unsigned long max_memkb;
-
- static char *kwd_list[] = { "dom", "max_memkb", NULL };
-
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list,
- &dom, &max_memkb) )
- return NULL;
-
- if ( xc_domain_setmaxmem(xc->xc_handle, dom, max_memkb) != 0 )
- return PyErr_SetFromErrno(xc_error);
-
- Py_INCREF(zero);
- return zero;
-}
-
-
-static PyMethodDef pyxc_methods[] = {
- { "domain_create",
- (PyCFunction)pyxc_domain_create,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Create a new domain.\n"
- " mem_kb [int, 0]: Memory allocation, in kilobytes.\n"
- " name [str, '(anon)']: Informative textual name.\n\n"
- "Returns: [int] new domain identifier; -1 on error.\n" },
-
- { "domain_pause",
- (PyCFunction)pyxc_domain_pause,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Temporarily pause execution of a domain.\n"
- " dom [int]: Identifier of domain to be paused.\n\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { "domain_unpause",
- (PyCFunction)pyxc_domain_unpause,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "(Re)start execution of a domain.\n"
- " dom [int]: Identifier of domain to be unpaused.\n\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { "domain_destroy",
- (PyCFunction)pyxc_domain_destroy,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Destroy a domain.\n"
- " dom [int]: Identifier of domain to be destroyed.\n\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { "domain_pincpu",
- (PyCFunction)pyxc_domain_pincpu,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Pin a domain to a specified CPU.\n"
- " dom [int]: Identifier of domain to be pinned.\n"
- " cpu [int, -1]: CPU to pin to, or -1 to unpin\n\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { "domain_getinfo",
- (PyCFunction)pyxc_domain_getinfo,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Get information regarding a set of domains, in increasing id order.\n"
- " first_dom [int, 0]: First domain to retrieve info about.\n"
- " max_doms [int, 1024]: Maximum number of domains to retrieve info"
- " about.\n\n"
- "Returns: [list of dicts] if list length is less than 'max_doms'\n"
- " parameter then there was an error, or the end of the\n"
- " domain-id space was reached.\n"
- " dom [int]: Identifier of domain to which this info pertains\n"
- " cpu [int]: CPU to which this domain is bound\n"
- " dying [int]: Bool - is the domain dying?\n"
- " crashed [int]: Bool - has the domain crashed?\n"
- " shutdown [int]: Bool - has the domain shut itself down?\n"
- " paused [int]: Bool - is the domain paused by control software?\n"
- " blocked [int]: Bool - is the domain blocked waiting for an event?\n"
- " running [int]: Bool - is the domain currently running?\n"
- " mem_kb [int]: Memory reservation, in kilobytes\n"
- " cpu_time [long]: CPU time consumed, in nanoseconds\n"
- " name [str]: Identifying name\n"
- " shutdown_reason [int]: Numeric code from guest OS, explaining "
- "reason why it shut itself down.\n" },
-
- { "linux_save",
- (PyCFunction)pyxc_linux_save,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Save the CPU and memory state of a Linux guest OS.\n"
- " dom [int]: Identifier of domain to be saved.\n"
- " state_file [str]: Name of state file. Must not currently exist.\n"
- " progress [int, 1]: Bool - display a running progress indication?\n\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { "linux_restore",
- (PyCFunction)pyxc_linux_restore,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Restore the CPU and memory state of a Linux guest OS.\n"
- " state_file [str]: Name of state file. Must not currently exist.\n"
- " progress [int, 1]: Bool - display a running progress indication?\n\n"
- "Returns: [int] new domain identifier on success; -1 on error.\n" },
-
- { "linux_build",
- (PyCFunction)pyxc_linux_build,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Build a new Linux guest OS.\n"
- " dom [int]: Identifier of domain to build into.\n"
- " image [str]: Name of kernel image file. May be gzipped.\n"
- " ramdisk [str, n/a]: Name of ramdisk file, if any.\n"
- " cmdline [str, n/a]: Kernel parameters, if any.\n\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { "netbsd_build",
- (PyCFunction)pyxc_netbsd_build,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Build a new NetBSD guest OS.\n"
- " dom [int]: Identifier of domain to build into.\n"
- " image [str]: Name of kernel image file. May be gzipped.\n"
- " cmdline [str, n/a]: Kernel parameters, if any.\n\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { "bvtsched_global_set",
- (PyCFunction)pyxc_bvtsched_global_set,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Set global tuning parameters for Borrowed Virtual Time scheduler.\n"
- " ctx_allow [int]: Minimal guaranteed quantum.\n\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { "bvtsched_global_get",
- (PyCFunction)pyxc_bvtsched_global_get,
- METH_KEYWORDS, "\n"
- "Get global tuning parameters for BVT scheduler.\n"
- "Returns: [dict]:\n"
- " ctx_allow [int]: context switch allowance\n" },
-
- { "bvtsched_domain_set",
- (PyCFunction)pyxc_bvtsched_domain_set,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Set per-domain tuning parameters for Borrowed Virtual Time scheduler.\n"
- " dom [int]: Identifier of domain to be tuned.\n"
- " mcuadv [int]: Proportional to the inverse of the domain's weight.\n"
- " warp [int]: How far to warp domain's EVT on unblock.\n"
- " warpl [int]: How long the domain can run warped.\n"
- " warpu [int]: How long before the domain can warp again.\n\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { "bvtsched_domain_get",
- (PyCFunction)pyxc_bvtsched_domain_get,
- METH_KEYWORDS, "\n"
- "Get per-domain tuning parameters under the BVT scheduler.\n"
- " dom [int]: Identifier of domain to be queried.\n"
- "Returns [dict]:\n"
- " domain [int]: Domain ID.\n"
- " mcuadv [long]: MCU Advance.\n"
- " warp [long]: Warp.\n"
- " warpu [long]: Unwarp requirement.\n"
- " warpl [long]: Warp limit,\n"
- },
-
- { "atropos_domain_set",
- (PyCFunction)pyxc_atropos_domain_set,
- METH_KEYWORDS, "\n"
- "Set the scheduling parameters for a domain when running with Atropos.\n"
- " dom [int]: domain to set\n"
- " period [long]: domain's scheduling period\n"
- " slice [long]: domain's slice per period\n"
- " latency [long]: wakeup latency hint\n"
- " xtratime [int]: boolean\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { "atropos_domain_get",
- (PyCFunction)pyxc_atropos_domain_get,
- METH_KEYWORDS, "\n"
- "Get the current scheduling parameters for a domain when running with\n"
- "the Atropos scheduler."
- " dom [int]: domain to query\n"
- "Returns: [dict]\n"
- " domain [int]: domain ID\n"
- " period [long]: scheduler period\n"
- " slice [long]: CPU reservation per period\n"
- " latency [long]: unblocking latency hint\n"
- " xtratime [int] : 0 if not using slack time, nonzero otherwise\n" },
-
- { "rrobin_global_set",
- (PyCFunction)pyxc_rrobin_global_set,
- METH_KEYWORDS, "\n"
- "Set Round Robin scheduler slice.\n"
- " slice [long]: Round Robin scheduler slice\n"
- "Returns: [int] 0 on success, throws an exception on failure\n" },
-
- { "rrobin_global_get",
- (PyCFunction)pyxc_rrobin_global_get,
- METH_KEYWORDS, "\n"
- "Get Round Robin scheduler settings\n"
- "Returns [dict]:\n"
- " slice [long]: Scheduler time slice.\n" },
-
- { "evtchn_bind_interdomain",
- (PyCFunction)pyxc_evtchn_bind_interdomain,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Open an event channel between two domains.\n"
- " dom1 [int, SELF]: First domain to be connected.\n"
- " dom2 [int, SELF]: Second domain to be connected.\n\n"
- "Returns: [dict] dictionary is empty on failure.\n"
- " port1 [int]: Port-id for endpoint at dom1.\n"
- " port2 [int]: Port-id for endpoint at dom2.\n" },
-
- { "evtchn_bind_virq",
- (PyCFunction)pyxc_evtchn_bind_virq,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Bind an event channel to the specified VIRQ.\n"
- " virq [int]: VIRQ to bind.\n\n"
- "Returns: [int] Bound event-channel port.\n" },
-
- { "evtchn_close",
- (PyCFunction)pyxc_evtchn_close,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Close an event channel.\n"
- " dom [int, SELF]: Dom-id of one endpoint of the channel.\n"
- " port [int]: Port-id of one endpoint of the channel.\n\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { "evtchn_send",
- (PyCFunction)pyxc_evtchn_send,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Send an event along a locally-connected event channel.\n"
- " port [int]: Port-id of a local channel endpoint.\n\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { "evtchn_status",
- (PyCFunction)pyxc_evtchn_status,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Query the status of an event channel.\n"
- " dom [int, SELF]: Dom-id of one endpoint of the channel.\n"
- " port [int]: Port-id of one endpoint of the channel.\n\n"
- "Returns: [dict] dictionary is empty on failure.\n"
- " status [str]: 'closed', 'unbound', 'interdomain', 'pirq',"
- " or 'virq'.\n"
- "The following are returned if 'status' is 'interdomain':\n"
- " dom [int]: Dom-id of remote endpoint.\n"
- " port [int]: Port-id of remote endpoint.\n"
- "The following are returned if 'status' is 'pirq' or 'virq':\n"
- " irq [int]: IRQ number.\n" },
-
- { "physdev_pci_access_modify",
- (PyCFunction)pyxc_physdev_pci_access_modify,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Allow a domain access to a PCI device\n"
- " dom [int]: Identifier of domain to be allowed access.\n"
- " bus [int]: PCI bus\n"
- " dev [int]: PCI slot\n"
- " func [int]: PCI function\n"
- " enable [int]: Non-zero means enable access; else disable access\n\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { "readconsolering",
- (PyCFunction)pyxc_readconsolering,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Read Xen's console ring.\n"
- " clear [int, 0]: Bool - clear the ring after reading from it?\n\n"
- "Returns: [str] string is empty on failure.\n" },
-
- { "physinfo",
- (PyCFunction)pyxc_physinfo,
- METH_VARARGS, "\n"
- "Get information about the physical host machine\n"
- "Returns [dict]: information about the hardware"
- " [None]: on failure.\n" },
-
- { "shadow_control",
- (PyCFunction)pyxc_shadow_control,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Set parameter for shadow pagetable interface\n"
- " dom [int]: Identifier of domain.\n"
- " op [int, 0]: operation\n\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { "domain_setname",
- (PyCFunction)pyxc_domain_setname,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Set domain informative textual name\n"
- " dom [int]: Identifier of domain.\n"
- " name [str]: Text string.\n\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { "domain_setmaxmem",
- (PyCFunction)pyxc_domain_setname,
- METH_VARARGS | METH_KEYWORDS, "\n"
- "Set a domain's memory limit\n"
- " dom [int]: Identifier of domain.\n"
- " max_memkb [long]: .\n"
- "Returns: [int] 0 on success; -1 on error.\n" },
-
- { NULL, NULL, 0, NULL }
-};
-
-
-/*
- * Definitions for the 'Xc' module wrapper.
- */
-
-staticforward PyTypeObject PyXcType;
-
-static PyObject *PyXc_new(PyObject *self, PyObject *args)
-{
- XcObject *xc;
-
- if ( !PyArg_ParseTuple(args, ":new") )
- return NULL;
-
- xc = PyObject_New(XcObject, &PyXcType);
-
- if ( (xc->xc_handle = xc_interface_open()) == -1 )
- {
- PyObject_Del((PyObject *)xc);
- return PyErr_SetFromErrno(xc_error);
- }
-
- return (PyObject *)xc;
-}
-
-static PyObject *PyXc_getattr(PyObject *obj, char *name)
-{
- return Py_FindMethod(pyxc_methods, obj, name);
-}
-
-static void PyXc_dealloc(PyObject *self)
-{
- XcObject *xc = (XcObject *)self;
- (void)xc_interface_close(xc->xc_handle);
- PyObject_Del(self);
-}
-
-static PyTypeObject PyXcType = {
- PyObject_HEAD_INIT(&PyType_Type)
- 0,
- "Xc",
- sizeof(XcObject),
- 0,
- PyXc_dealloc, /* tp_dealloc */
- NULL, /* tp_print */
- PyXc_getattr, /* tp_getattr */
- NULL, /* tp_setattr */
- NULL, /* tp_compare */
- NULL, /* tp_repr */
- NULL, /* tp_as_number */
- NULL, /* tp_as_sequence */
- NULL, /* tp_as_mapping */
- NULL /* tp_hash */
-};
-
-static PyMethodDef PyXc_methods[] = {
- { "new", PyXc_new, METH_VARARGS, "Create a new " XENPKG " object." },
- { NULL, NULL, 0, NULL }
-};
-
-PyMODINIT_FUNC initxc(void)
-{
- PyObject *m, *d;
-
- m = Py_InitModule(XENPKG, PyXc_methods);
-
- d = PyModule_GetDict(m);
- xc_error = PyErr_NewException(XENPKG ".error", NULL, NULL);
- PyDict_SetItemString(d, "error", xc_error);
-
- zero = PyInt_FromLong(0);
-}
+++ /dev/null
-
-from distutils.core import setup, Extension
-
-module = Extension("xc",
- extra_compile_args = ["-fno-strict-aliasing"],
- include_dirs = ["../lib",
- "../../../xen/include/hypervisor-ifs",
- "../../../linux-xen-sparse/include",
- "../../xu/lib",
- "../../lib" ],
- library_dirs = ["../lib",
- "../../lib" ],
- libraries = ["xc"],
- sources = ["Xc.c"])
-
-setup(name = "xc",
- version = "2.0",
- ext_package = "xen.ext",
- ext_modules = [module])
+++ /dev/null
-
-all:
- python setup.py build
-
-install: all
- if [ "$(prefix)" = "" ]; then \
- python setup.py install; \
- elif [ "$(dist)" = "yes" ]; then \
- python setup.py install --home="$(prefix)"; \
- else \
- python setup.py install --root="$(prefix)"; \
- fi
- mkdir -p $(prefix)/usr/sbin
- install -m0755 xend $(prefix)/usr/sbin
- install -m0755 xm $(prefix)/usr/sbin
- mkdir -p $(prefix)/etc/xen/xend
- install -m0755 vifctl $(prefix)/etc/xen/xend
-
-clean:
- rm -rf build *.pyc *.pyo *.o *.a *~
+++ /dev/null
-"""Bridge control utilities.
-"""
-import os
-import os.path
-import re
-import sys
-
-os.defpath = os.defpath + ':/sbin:/usr/sbin:/usr/local/sbin'
-CMD_IFCONFIG = 'ifconfig'
-CMD_ROUTE = 'route'
-CMD_BRCTL = 'brctl'
-CMD_IPTABLES = "iptables"
-
-opts = None
-
-class Opts:
-
- def __init__(self, defaults):
- for (k, v) in defaults.items():
- setattr(self, k, v)
- pass
-
-def cmd(p, s):
- """Print and execute command 'p' with args 's'.
- """
- global opts
- c = p + ' ' + s
- if opts.verbose: print c
- if not opts.dryrun:
- os.system(c)
-
-def vif_bridge_add(params):
- """Add the network interface for vif on dom to a bridge.
- """
- cmd(CMD_BRCTL, 'addif %(bridge)s %(vif)s' % params)
-
-def vif_bridge_rem(params):
- """Remove the network interface for vif on dom from a bridge.
- """
- cmd(CMD_BRCTL, 'delif %(bridge)s %(vif)s' % params)
-
-def vif_restrict_addr(vif, addr, delete=0):
- d = { 'vif': vif, 'addr': addr}
- if delete:
- d['flag'] = '-D'
- else:
- d['flag'] = '-A'
- cmd(CMD_IPTABLES, '-P FORWARD DROP')
- cmd(CMD_IPTABLES, '%(flag)s FORWARD -m physdev --physdev-in %(vif)s -s %(addr)s -j ACCEPT' % d)
- cmd(CMD_IPTABLES, '%(flag)s FORWARD -m physdev --physdev-out %(vif)s -d %(addr)s -j ACCEPT' % d)
-
-def bridge_create(bridge, **kwd):
- """Create a bridge.
- Defaults hello time to 0, forward delay to 0 and stp off.
- """
- cmd(CMD_BRCTL, 'addbr %s' % bridge)
- if kwd.get('hello', None) is None:
- kwd['hello'] = 0
- if kwd.get('fd', None) is None:
- kwd['fd'] = 0
- if kwd.get('stp', None) is None:
- kwd['stp'] = 'off'
- bridge_set(bridge, **kwd)
-
-def bridge_set(bridge, hello=None, fd=None, stp=None):
- """Set bridge parameters.
- """
- if hello is not None:
- cmd(CMD_BRCTL, 'sethello %s %d' % (bridge, hello))
- if fd is not None:
- cmd(CMD_BRCTL, 'setfd %s %d' % (bridge, fd))
- if stp is not None:
- cmd(CMD_BRCTL, 'stp %s %s' % (bridge, stp))
-
-def bridge_del(bridge):
- """Delete a bridge.
- """
- cmd(CMD_BRCTL, 'delbr %s' % bridge)
-
-def routes():
- """Return a list of the routes.
- """
- fin = os.popen(CMD_ROUTE + ' -n', 'r')
- routes = []
- for x in fin:
- if x.startswith('Kernel'): continue
- if x.startswith('Destination'): continue
- x = x.strip()
- y = x.split()
- z = { 'destination': y[0],
- 'gateway' : y[1],
- 'mask' : y[2],
- 'flags' : y[3],
- 'metric' : y[4],
- 'ref' : y[5],
- 'use' : y[6],
- 'interface' : y[7] }
- routes.append(z)
- return routes
-
-def ifconfig(interface):
- """Return the ip config for an interface,
- """
- fin = os.popen(CMD_IFCONFIG + ' %s' % interface, 'r')
- inetre = re.compile('\s*inet\s*addr:(?P<address>\S*)\s*Bcast:(?P<broadcast>\S*)\s*Mask:(?P<mask>\S*)')
- info = None
- for x in fin:
- m = inetre.match(x)
- if not m: continue
- info = m.groupdict()
- info['interface'] = interface
- break
- return info
-
-def reconfigure(interface, bridge):
- """Reconfigure an interface to be attached to a bridge, and give the bridge
- the IP address etc. from interface. Move the default route to the interface
- to the bridge.
-
- """
- global opts
- intf_info = ifconfig(interface)
- if not intf_info:
- print >>sys.stderr, 'Interface not found:', interface
- return
- #bridge_info = ifconfig(bridge)
- #if not bridge_info:
- # print >>sys.stderr, 'Bridge not found:', bridge
- # return
- route_info = routes()
- intf_info['bridge'] = bridge
- intf_info['gateway'] = None
- for r in route_info:
- if (r['destination'] == '0.0.0.0' and
- 'G' in r['flags'] and
- r['interface'] == interface):
- intf_info['gateway'] = r['gateway']
- if not intf_info['gateway']:
- print >>sys.stderr, 'Gateway not found: ', interface
- return
- cmd(CMD_IFCONFIG,
- '%(bridge)s %(address)s netmask %(mask)s broadcast %(broadcast)s up'
- % intf_info)
- cmd(CMD_ROUTE,
- 'add default gateway %(gateway)s dev %(bridge)s'
- % intf_info)
- cmd(CMD_BRCTL, 'addif %(bridge)s %(interface)s' % intf_info)
- cmd(CMD_IFCONFIG, '%(interface)s 0.0.0.0' % intf_info)
-
-defaults = {
- 'verbose' : 1,
- 'dryrun' : 0,
- }
-
-opts = Opts(defaults)
-
-def set_opts(val):
- global opts
- opts = val
- return opts
+++ /dev/null
-#!/usr/bin/env python
-
-##############################################
-# Console client for Xen guest OSes
-# Copyright (c) 2004, K A Fraser
-##############################################
-
-import errno, os, signal, socket, struct, sys
-
-from termios import *
-# Indexes into termios.tcgetattr() list.
-IFLAG = 0
-OFLAG = 1
-CFLAG = 2
-LFLAG = 3
-ISPEED = 4
-OSPEED = 5
-CC = 6
-
-def __child_death(signum, frame):
- global stop
- stop = True
-
-def __recv_from_sock(sock):
- global stop
- stop = False
- while not stop:
- try:
- data = sock.recv(1024)
- os.write(1, data)
- except socket.error, error:
- if error[0] != errno.EINTR:
- raise
- os.wait()
-
-def __send_to_sock(sock):
- while 1:
- data = os.read(0,1024)
- if ord(data[0]) == ord(']')-64:
- break
- try:
- sock.send(data)
- except socket.error, error:
- if error[0] == errno.EPIPE:
- sys.exit(0)
- if error[0] != errno.EINTR:
- raise
- sys.exit(0)
-
-def connect(host,port):
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
- sock.connect((host,port))
-
- oattrs = tcgetattr(0)
- nattrs = tcgetattr(0)
- nattrs[IFLAG] = nattrs[IFLAG] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON)
- nattrs[OFLAG] = nattrs[OFLAG] & ~(OPOST)
- nattrs[CFLAG] = nattrs[CFLAG] & ~(CSIZE | PARENB)
- nattrs[CFLAG] = nattrs[CFLAG] | CS8
- nattrs[LFLAG] = nattrs[LFLAG] & ~(ECHO | ICANON | IEXTEN | ISIG)
- nattrs[CC][VMIN] = 1
- nattrs[CC][VTIME] = 0
-
- if os.fork():
- signal.signal(signal.SIGCHLD, __child_death)
- print "************ REMOTE CONSOLE: CTRL-] TO QUIT ********"
- tcsetattr(0, TCSAFLUSH, nattrs)
- try:
- __recv_from_sock(sock)
- finally:
- tcsetattr(0, TCSAFLUSH, oattrs)
- print
- print "************ REMOTE CONSOLE EXITED *****************"
- else:
- signal.signal(signal.SIGPIPE, signal.SIG_IGN)
- __send_to_sock(sock)
-
-if __name__ == '__main__':
- if len(sys.argv) != 3:
- print sys.argv[0] + " <host> <port>"
- sys.exit(1)
- connect(str(sys.argv[1]),int(sys.argv[2]))
+++ /dev/null
-import os
-import re
-import socket
-import struct
-
-def readlines(fd):
- """Version of readlines safe against EINTR.
- """
- import errno
-
- lines = []
- while 1:
- try:
- line = fd.readline()
- except IOError, ex:
- if ex.errno == errno.EINTR:
- continue
- else:
- raise
- if line == '': break
- lines.append(line)
- return lines
-
-def readline(fd):
- """Version of readline safe against EINTR.
- """
- while 1:
- try:
- return fd.readline()
- except IOError, ex:
- if ex.errno == errno.EINTR:
- continue
- else:
- raise
-
-##### Networking-related functions
-
-"""Bridge for network backend.
-When bridging is used, eth0 may not have an IP address,
-as it may have been moved onto the bridge.
-"""
-NBE_BRIDGE = 'nbe-br'
-
-def get_current_ipaddr(dev='eth0'):
- """Return a string containing the primary IP address for the given
- network interface (default 'eth0').
- """
- fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
- lines = readlines(fd)
- for line in lines:
- m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
- line )
- if m:
- return m.group(1)
- if dev == 'eth0':
- return get_current_ipaddr(NBE_BRIDGE)
- return None
-
-def get_current_ipmask(dev='eth0'):
- """Return a string containing the primary IP netmask for the given
- network interface (default 'eth0').
- """
- fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
- lines = readlines(fd)
- for line in lines:
- m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
- line )
- if m:
- return m.group(1)
- if dev == 'eth0':
- return get_current_ipmask(NBE_BRIDGE)
- return None
-
-def get_current_ipgw(dev='eth0'):
- """Return a string containing the IP gateway for the given
- network interface (default 'eth0').
- """
- fd = os.popen( '/sbin/route -n' )
- lines = readlines(fd)
- for line in lines:
- m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' +
- '\s+\S+\s+\S*G.*' + dev + '.*', line )
- if m:
- return m.group(1)
- if dev == 'eth0':
- return get_current_ipgw(NBE_BRIDGE)
- return None
-
-def inet_aton(addr):
- """Convert an IP addr in IPv4 dot notation into an int.
- """
- b = socket.inet_aton(addr)
- return struct.unpack('!I', b)[0]
-
-def inet_ntoa(n):
- """Convert an int into an IP addr in IPv4 dot notation.
- """
- b = struct.pack('!I', n)
- return socket.inet_ntoa(b)
-
-def add_offset_to_ip(addr, offset):
- """Add a numerical offset to an IP addr in IPv4 dot notation.
- """
- n = inet_aton(addr)
- n += offset
- return inet_ntoa(n)
-
-def check_subnet( ip, network, netmask ):
- n_ip = inet_aton(ip)
- n_net = inet_aton(network)
- n_mask = inet_aton(netmask)
- return (n_ip & n_mask) == (n_net & n_mask)
-
+++ /dev/null
-"""Temporary files.
-
-This module provides generic, low- and high-level interfaces for
-creating temporary files and directories. The interfaces listed
-as "safe" just below can be used without fear of race conditions.
-Those listed as "unsafe" cannot, and are provided for backward
-compatibility only.
-
-This module also provides some data items to the user:
-
- TMP_MAX - maximum number of names that will be tried before
- giving up.
- template - the default prefix for all temporary names.
- You may change this to control the default prefix.
- tempdir - If this is set to a string before the first use of
- any routine from this module, it will be considered as
- another candidate location to store temporary files.
-"""
-
-__all__ = [
- "NamedTemporaryFile", "TemporaryFile", # high level safe interfaces
- "mkstemp", "mkdtemp", # low level safe interfaces
- "mktemp", # deprecated unsafe interface
- "TMP_MAX", "gettempprefix", # constants
- "tempdir", "gettempdir"
- ]
-
-
-# Imports.
-
-import os as _os
-import errno as _errno
-from random import Random as _Random
-
-if _os.name == 'mac':
- import Carbon.Folder as _Folder
- import Carbon.Folders as _Folders
-
-try:
- import fcntl as _fcntl
- # If PYTHONCASEOK is set on Windows, stinking FCNTL.py gets
- # imported, and we don't get an ImportError then. Provoke
- # an AttributeError instead in that case.
- _fcntl.fcntl
-except (ImportError, AttributeError):
- def _set_cloexec(fd):
- pass
-else:
- def _set_cloexec(fd):
- flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0)
- if flags >= 0:
- # flags read successfully, modify
- flags |= _fcntl.FD_CLOEXEC
- _fcntl.fcntl(fd, _fcntl.F_SETFD, flags)
-
-
-try:
- import thread as _thread
-except ImportError:
- import dummy_thread as _thread
-_allocate_lock = _thread.allocate_lock
-
-_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL
-if hasattr(_os, 'O_NOINHERIT'):
- _text_openflags |= _os.O_NOINHERIT
-if hasattr(_os, 'O_NOFOLLOW'):
- _text_openflags |= _os.O_NOFOLLOW
-
-_bin_openflags = _text_openflags
-if hasattr(_os, 'O_BINARY'):
- _bin_openflags |= _os.O_BINARY
-
-if hasattr(_os, 'TMP_MAX'):
- TMP_MAX = _os.TMP_MAX
-else:
- TMP_MAX = 10000
-
-template = "tmp"
-
-tempdir = None
-
-# Internal routines.
-
-_once_lock = _allocate_lock()
-
-class _RandomNameSequence:
- """An instance of _RandomNameSequence generates an endless
- sequence of unpredictable strings which can safely be incorporated
- into file names. Each string is six characters long. Multiple
- threads can safely use the same instance at the same time.
-
- _RandomNameSequence is an iterator."""
-
- characters = ("abcdefghijklmnopqrstuvwxyz" +
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
- "0123456789-_")
-
- def __init__(self):
- self.mutex = _allocate_lock()
- self.rng = _Random()
- self.normcase = _os.path.normcase
-
- def __iter__(self):
- return self
-
- def next(self):
- m = self.mutex
- c = self.characters
- choose = self.rng.choice
-
- m.acquire()
- try:
- letters = [choose(c) for dummy in "123456"]
- finally:
- m.release()
-
- return self.normcase(''.join(letters))
-
-def _candidate_tempdir_list():
- """Generate a list of candidate temporary directories which
- _get_default_tempdir will try."""
-
- dirlist = []
-
- # First, try the environment.
- for envname in 'TMPDIR', 'TEMP', 'TMP':
- dirname = _os.getenv(envname)
- if dirname: dirlist.append(dirname)
-
- # Failing that, try OS-specific locations.
- if _os.name == 'mac':
- try:
- fsr = _Folder.FSFindFolder(_Folders.kOnSystemDisk,
- _Folders.kTemporaryFolderType, 1)
- dirname = fsr.as_pathname()
- dirlist.append(dirname)
- except _Folder.error:
- pass
- elif _os.name == 'riscos':
- dirname = _os.getenv('Wimp$ScrapDir')
- if dirname: dirlist.append(dirname)
- elif _os.name == 'nt':
- dirlist.extend([ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ])
- else:
- dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ])
-
- # As a last resort, the current directory.
- try:
- dirlist.append(_os.getcwd())
- except (AttributeError, _os.error):
- dirlist.append(_os.curdir)
-
- return dirlist
-
-def _get_default_tempdir():
- """Calculate the default directory to use for temporary files.
- This routine should be called exactly once.
-
- We determine whether or not a candidate temp dir is usable by
- trying to create and write to a file in that directory. If this
- is successful, the test file is deleted. To prevent denial of
- service, the name of the test file must be randomized."""
-
- namer = _RandomNameSequence()
- dirlist = _candidate_tempdir_list()
- flags = _text_openflags
-
- for dir in dirlist:
- if dir != _os.curdir:
- dir = _os.path.normcase(_os.path.abspath(dir))
- # Try only a few names per directory.
- for seq in xrange(100):
- name = namer.next()
- filename = _os.path.join(dir, name)
- try:
- fd = _os.open(filename, flags, 0600)
- fp = _os.fdopen(fd, 'w')
- fp.write('blat')
- fp.close()
- _os.unlink(filename)
- del fp, fd
- return dir
- except (OSError, IOError), e:
- if e[0] != _errno.EEXIST:
- break # no point trying more names in this directory
- pass
- raise IOError, (_errno.ENOENT,
- ("No usable temporary directory found in %s" % dirlist))
-
-_name_sequence = None
-
-def _get_candidate_names():
- """Common setup sequence for all user-callable interfaces."""
-
- global _name_sequence
- if _name_sequence is None:
- _once_lock.acquire()
- try:
- if _name_sequence is None:
- _name_sequence = _RandomNameSequence()
- finally:
- _once_lock.release()
- return _name_sequence
-
-
-def _mkstemp_inner(dir, pre, suf, flags):
- """Code common to mkstemp, TemporaryFile, and NamedTemporaryFile."""
-
- names = _get_candidate_names()
-
- for seq in xrange(TMP_MAX):
- name = names.next()
- file = _os.path.join(dir, pre + name + suf)
- try:
- fd = _os.open(file, flags, 0600)
- _set_cloexec(fd)
- return (fd, file)
- except OSError, e:
- if e.errno == _errno.EEXIST:
- continue # try again
- raise
-
- raise IOError, (_errno.EEXIST, "No usable temporary file name found")
-
-
-# User visible interfaces.
-
-def gettempprefix():
- """Accessor for tempdir.template."""
- return template
-
-tempdir = None
-
-def gettempdir():
- """Accessor for tempdir.tempdir."""
- global tempdir
- if tempdir is None:
- _once_lock.acquire()
- try:
- if tempdir is None:
- tempdir = _get_default_tempdir()
- finally:
- _once_lock.release()
- return tempdir
-
-def mkstemp(suffix="", prefix=template, dir=None, text=False):
- """mkstemp([suffix, [prefix, [dir, [text]]]])
- User-callable function to create and return a unique temporary
- file. The return value is a pair (fd, name) where fd is the
- file descriptor returned by os.open, and name is the filename.
-
- If 'suffix' is specified, the file name will end with that suffix,
- otherwise there will be no suffix.
-
- If 'prefix' is specified, the file name will begin with that prefix,
- otherwise a default prefix is used.
-
- If 'dir' is specified, the file will be created in that directory,
- otherwise a default directory is used.
-
- If 'text' is specified and true, the file is opened in text
- mode. Else (the default) the file is opened in binary mode. On
- some operating systems, this makes no difference.
-
- The file is readable and writable only by the creating user ID.
- If the operating system uses permission bits to indicate whether a
- file is executable, the file is executable by no one. The file
- descriptor is not inherited by children of this process.
-
- Caller is responsible for deleting the file when done with it.
- """
-
- if dir is None:
- dir = gettempdir()
-
- if text:
- flags = _text_openflags
- else:
- flags = _bin_openflags
-
- return _mkstemp_inner(dir, prefix, suffix, flags)
-
-
-def mkdtemp(suffix="", prefix=template, dir=None):
- """mkdtemp([suffix, [prefix, [dir]]])
- User-callable function to create and return a unique temporary
- directory. The return value is the pathname of the directory.
-
- Arguments are as for mkstemp, except that the 'text' argument is
- not accepted.
-
- The directory is readable, writable, and searchable only by the
- creating user.
-
- Caller is responsible for deleting the directory when done with it.
- """
-
- if dir is None:
- dir = gettempdir()
-
- names = _get_candidate_names()
-
- for seq in xrange(TMP_MAX):
- name = names.next()
- file = _os.path.join(dir, prefix + name + suffix)
- try:
- _os.mkdir(file, 0700)
- return file
- except OSError, e:
- if e.errno == _errno.EEXIST:
- continue # try again
- raise
-
- raise IOError, (_errno.EEXIST, "No usable temporary directory name found")
-
-def mktemp(suffix="", prefix=template, dir=None):
- """mktemp([suffix, [prefix, [dir]]])
- User-callable function to return a unique temporary file name. The
- file is not created.
-
- Arguments are as for mkstemp, except that the 'text' argument is
- not accepted.
-
- This function is unsafe and should not be used. The file name
- refers to a file that did not exist at some point, but by the time
- you get around to creating it, someone else may have beaten you to
- the punch.
- """
-
-## from warnings import warn as _warn
-## _warn("mktemp is a potential security risk to your program",
-## RuntimeWarning, stacklevel=2)
-
- if dir is None:
- dir = gettempdir()
-
- names = _get_candidate_names()
- for seq in xrange(TMP_MAX):
- name = names.next()
- file = _os.path.join(dir, prefix + name + suffix)
- if not _os.path.exists(file):
- return file
-
- raise IOError, (_errno.EEXIST, "No usable temporary filename found")
-
-class _TemporaryFileWrapper:
- """Temporary file wrapper
-
- This class provides a wrapper around files opened for
- temporary use. In particular, it seeks to automatically
- remove the file when it is no longer needed.
- """
-
- def __init__(self, file, name):
- self.file = file
- self.name = name
- self.close_called = False
-
- def __getattr__(self, name):
- file = self.__dict__['file']
- a = getattr(file, name)
- if type(a) != type(0):
- setattr(self, name, a)
- return a
-
- # NT provides delete-on-close as a primitive, so we don't need
- # the wrapper to do anything special. We still use it so that
- # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile.
- if _os.name != 'nt':
-
- # Cache the unlinker so we don't get spurious errors at
- # shutdown when the module-level "os" is None'd out. Note
- # that this must be referenced as self.unlink, because the
- # name TemporaryFileWrapper may also get None'd out before
- # __del__ is called.
- unlink = _os.unlink
-
- def close(self):
- if not self.close_called:
- self.close_called = True
- self.file.close()
- self.unlink(self.name)
-
- def __del__(self):
- self.close()
-
-def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="",
- prefix=template, dir=None):
- """Create and return a temporary file.
- Arguments:
- 'prefix', 'suffix', 'dir' -- as for mkstemp.
- 'mode' -- the mode argument to os.fdopen (default "w+b").
- 'bufsize' -- the buffer size argument to os.fdopen (default -1).
- The file is created as mkstemp() would do it.
-
- Returns a file object; the name of the file is accessible as
- file.name. The file will be automatically deleted when it is
- closed.
- """
-
- if dir is None:
- dir = gettempdir()
-
- if 'b' in mode:
- flags = _bin_openflags
- else:
- flags = _text_openflags
-
- # Setting O_TEMPORARY in the flags causes the OS to delete
- # the file when it is closed. This is only supported by Windows.
- if _os.name == 'nt':
- flags |= _os.O_TEMPORARY
-
- (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)
- file = _os.fdopen(fd, mode, bufsize)
- return _TemporaryFileWrapper(file, name)
-
-if _os.name != 'posix' or _os.sys.platform == 'cygwin':
- # On non-POSIX and Cygwin systems, assume that we cannot unlink a file
- # while it is open.
- TemporaryFile = NamedTemporaryFile
-
-else:
- def TemporaryFile(mode='w+b', bufsize=-1, suffix="",
- prefix=template, dir=None):
- """Create and return a temporary file.
- Arguments:
- 'prefix', 'suffix', 'directory' -- as for mkstemp.
- 'mode' -- the mode argument to os.fdopen (default "w+b").
- 'bufsize' -- the buffer size argument to os.fdopen (default -1).
- The file is created as mkstemp() would do it.
-
- Returns a file object. The file has no name, and will cease to
- exist when it is closed.
- """
-
- if dir is None:
- dir = gettempdir()
-
- if 'b' in mode:
- flags = _bin_openflags
- else:
- flags = _text_openflags
-
- (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)
- try:
- _os.unlink(name)
- return _os.fdopen(fd, mode, bufsize)
- except:
- _os.close(fd)
- raise
+++ /dev/null
-import sxp
-
-class ArgError(StandardError):
- pass
-
-class Args:
- """Argument encoding support for HTTP.
- """
-
- def __init__(self, paramspec, keyspec):
- self.arg_ord = []
- self.arg_dict = {}
- self.key_ord = []
- self.key_dict = {}
- for (name, type) in paramspec:
- self.arg_ord.append(name)
- self.arg_dict[name] = type
- for (name, type) in keyspec:
- self.key_ord.append(name)
- self.key_dict[name] = type
-
- def get_args(self, d, xargs=None):
- args = {}
- keys = {}
- params = []
- if xargs:
- self.split_args(xargs, args, keys)
- self.split_args(d, args, keys)
- for a in self.arg_ord:
- if a in args:
- params.append(args[a])
- else:
- raise ArgError('Missing parameter: %s' % a)
- return (params, keys)
-
- def split_args(self, d, args, keys):
- for (k, v) in d.items():
- if k in self.arg_dict:
- type = self.arg_dict[k]
- val = self.coerce(type, v)
- args[k] = val
- elif k in self.key_dict:
- type = self.key_dict[k]
- val = self.coerce(type, v)
- keys[k] = val
- else:
- raise ArgError('Invalid parameter: %s' % k)
-
- def get_form_args(self, f, xargs=None):
- d = {}
- for (k, v) in f.items():
- n = len(v)
- if ((k not in self.arg_dict) and
- (k not in self.key_dict)):
- continue
- if n == 0:
- continue
- elif n == 1:
- d[k] = v[0]
- else:
- raise ArgError('Too many values for %s' % k)
- return self.get_args(d, xargs=xargs)
-
- def coerce(self, type, v):
- try:
- if type == 'int':
- return int(v)
- if type == 'str':
- return str(v)
- if type == 'sxpr':
- return self.sxpr(v)
- except ArgError:
- raise
- except StandardError, ex:
- raise ArgError(str(ex))
-
- def sxpr(self, v):
- if instanceof(v, types.ListType):
- return v
- if instanceof(v, types.File) or hasattr(v, 'readline'):
- return sxpr_file(v)
- if instanceof(v, types.StringType):
- return sxpr_file(StringIO(v))
- return str(v)
-
- def sxpr_file(self, fin):
- try:
- vals = sxp.parse(fin)
- except:
- raise ArgError('Coercion to sxpr failed')
- if len(vals) == 1:
- return vals[0]
- else:
- raise ArgError('Too many sxprs')
-
- def call_with_args(self, fn, args, xargs=None):
- (params, keys) = self.get_args(args, xargs=xargs)
- fn(*params, **keys)
-
- def call_with_form_args(self, fn, fargs, xargs=None):
- (params, keys) = self.get_form_args(fargs, xargs=xargs)
- fn(*params, **keys)
-
-class ArgFn(Args):
- """Represent a remote HTTP operation as a function.
- Used on the client.
- """
-
- def __init__(self, fn, paramspec, keyspec={}):
- Args.__init__(self, paramspec, keyspec)
- self.fn = fn
-
- def __call__(self, fargs, xargs=None):
- return self.call_with_args(self.fn, fargs, xargs=xargs)
-
-class FormFn(Args):
- """Represent an operation as a function over a form.
- Used in the HTTP server.
- """
-
- def __init__(self, fn, paramspec, keyspec={}):
- Args.__init__(self, paramspec, keyspec)
- self.fn = fn
-
- def __call__(self, fargs, xargs=None):
- return self.call_with_form_args(self.fn, fargs, xargs=xargs)
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-"""Simple publish/subscribe event server.
-
-"""
-import string
-
-from twisted.internet import reactor
-
-# subscribe a.b.c h: map a.b.c -> h
-# subscribe a.b.* h: map a.b.* -> h
-# subscribe a.b.? h: map a.b.? -> h
-#
-# for event a.b.c.d:
-#
-# lookup a.b.c.d, call handlers
-#
-# lookup a.b.c.?, call handlers
-#
-# lookup a.b.c.d.*, call handlers
-# lookup a.b.c.*, call handlers
-# lookup a.b.*, call handlers
-# lookup a.*, call handlers
-# lookup *, call handlers
-
-# a.b.c.d = (a b c d)
-# a.b.c.? = (a b c _)
-# a.b.c.* = (a b c . _)
-
-class EventServer:
-
- DOT = '.'
- QUERY = '?'
- DOT_QUERY = DOT + QUERY
- STAR = '*'
- DOT_STAR = DOT + STAR
-
- def __init__(self, run=0):
- self.handlers = {}
- self.run = run
- self.queue = []
-
- def start(self):
- """Enable event handling. Sends any queued events.
- """
- self.run = 1
- for (e,v) in self.queue:
- self.inject(e, v)
- self.queue = []
-
- def stop(self):
- """Suspend event handling. Events injected while suspended
- are queued until we are started again.
- """
- self.run = 0
-
- def subscribe(self, event, handler):
- """Subscribe to an event. For example 'a.b.c.d'.
- A subcription like 'a.b.c.?' ending in '?' matches any value
- for the '?'. A subscription like 'a.b.c.*' ending in '*' matches
- any event type with the same prefix, 'a.b.c' in this case.
-
- event event name
- handler event handler fn(event, val)
- """
- hl = self.handlers.get(event)
- if hl is None:
- self.handlers[event] = [handler]
- else:
- hl.append(handler)
-
- def unsubscribe_all(self, event=None):
- """Unsubscribe all handlers for a given event, or all handlers.
-
- event event (optional)
- """
- if event == None:
- self.handlers.clear()
- elif event in self.handlers:
- del self.handlers[event]
-
- def unsubscribe(self, event, handler):
- """Unsubscribe a given event and handler.
-
- event event
- handler handler
- """
- hl = self.handlers.get(event)
- if hl is None:
- return
- if handler in hl:
- hl.remove(handler)
-
- def inject(self, event, val, async=1):
- """Inject an event. Handlers for it are called if running, otherwise
- it is queued.
-
- event event type
- val event value
- """
- if self.run:
- if async:
- reactor.callLater(0, self.call_handlers, event, val)
- else:
- self.notify_handlers(event, val)
- else:
- self.queue.append( (event, val) )
-
- def call_handlers(self, event, val):
- """Internal method to call event handlers.
- """
- #print ">event", event, val
- self.call_event_handlers(event, event, val)
- self.call_query_handlers(event, val)
- self.call_star_handlers(event, val)
-
- def call_event_handlers(self, key, event, val):
- """Call the handlers for an event.
- It is safe for handlers to subscribe or unsubscribe.
-
- key key for handler list
- event event type
- val event value
- """
- hl = self.handlers.get(key)
- if hl is None:
- return
- # Copy the handler list so that handlers can call
- # subscribe/unsubscribe safely - python list iteration
- # is not safe against list modification.
- for h in hl[:]:
- try:
- h(event, val)
- except:
- pass
-
- def call_query_handlers(self, event, val):
- """Call regex handlers for events matching 'event' that end in '?'.
-
- event event type
- val event value
- """
- dot_idx = event.rfind(self.DOT)
- if dot_idx == -1:
- self.call_event_handlers(self.QUERY, event, val)
- else:
- event_query = event[0:dot_idx] + self.DOT_QUERY
- self.call_event_handlers(event_query, event, val)
-
- def call_star_handlers(self, event, val):
- """Call regex handlers for events matching 'event' that end in '*'.
-
- event event type
- val event value
- """
- etype = string.split(event, self.DOT)
- for i in range(len(etype), 0, -1):
- event_star = self.DOT.join(etype[0:i]) + self.DOT_STAR
- self.call_event_handlers(event_star, event, val)
- self.call_event_handlers(self.STAR, event, val)
-
-def instance():
- global inst
- try:
- inst
- except:
- inst = EventServer()
- inst.start()
- return inst
-
-def main():
- def sys_star(event, val):
- print 'sys_star', event, val
-
- def sys_foo(event, val):
- print 'sys_foo', event, val
- s.unsubscribe('sys.foo', sys_foo)
-
- def sys_foo2(event, val):
- print 'sys_foo2', event, val
-
- def sys_bar(event, val):
- print 'sys_bar', event, val
-
- def sys_foo_bar(event, val):
- print 'sys_foo_bar', event, val
-
- def foo_bar(event, val):
- print 'foo_bar', event, val
-
- s = EventServer()
- s.start()
- s.subscribe('sys.*', sys_star)
- s.subscribe('sys.foo', sys_foo)
- s.subscribe('sys.foo', sys_foo2)
- s.subscribe('sys.bar', sys_bar)
- s.subscribe('sys.foo.bar', sys_foo_bar)
- s.subscribe('foo.bar', foo_bar)
- s.inject('sys.foo', 'hello')
- print
- s.inject('sys.bar', 'hello again')
- print
- s.inject('sys.foo.bar', 'hello again')
- print
- s.inject('foo.bar', 'hello again')
- print
- s.inject('foo', 'hello again')
- print
- s.start()
- s.unsubscribe('sys.*', sys_star)
- s.unsubscribe_all('sys.*')
- s.inject('sys.foo', 'hello')
-
-if __name__ == "__main__":
- main()
-
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-## XEND_DOMAIN_CREATE = "xend.domain.create": dom
-## create:
-## xend.domain.destroy: dom, reason:died/crashed
-## xend.domain.up ?
-
-## xend.domain.unpause: dom
-## xend.domain.pause: dom
-## xend.domain.shutdown: dom
-## xend.domain.destroy: dom
-
-## xend.domain.migrate.begin: dom, to
-## Begin tells: src host, src domain uri, dst host. Dst id known?
-## err: src host, src domain uri, dst host, dst id if known, status (of domain: ok, dead,...), reason
-## end: src host, src domain uri, dst host, dst uri
-
-## Events for both ends of migrate: for exporter and importer?
-## Include migrate id so can tie together.
-## Have uri /xend/migrate/<id> for migrate info (migrations in progress).
-
-## (xend.domain.migrate.begin (src <host>) (src.domain <id>)
-## (dst <host>) (id <migrate id>))
-
-## xend.domain.migrate.end:
-## (xend.domain.migrate.end (domain <id>) (to <host>)
-
-## xend.node.up: xend uri
-## xend.node.down: xend uri
-
-## xend.error ?
-
-## format:
-
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-"""General pretty-printer, including support for SXP.
-
-"""
-import sys
-import types
-import StringIO
-import sxp
-
-class PrettyItem:
-
- def __init__(self, width):
- self.width = width
-
- def insert(self, block):
- block.addtoline(self)
-
- def get_width(self):
- return self.width
-
- def output(self, out):
- print '***PrettyItem>output>', self
- pass
-
- def prettyprint(self, out, width):
- print '***PrettyItem>prettyprint>', self
- return width
-
-class PrettyString(PrettyItem):
-
- def __init__(self, x):
- PrettyItem.__init__(self, len(x))
- self.value = x
-
- def output(self, out):
- out.write(self.value)
-
- def prettyprint(self, line):
- line.output(self)
-
- def show(self, out):
- print >> out, ("(string (width %d) '%s')" % (self.width, self.value))
-
-class PrettySpace(PrettyItem):
-
- def output(self, out):
- out.write(' ' * self.width)
-
- def prettyprint(self, line):
- line.output(self)
-
- def show(self, out):
- print >> out, ("(space (width %d))" % self.width)
-
-class PrettyBreak(PrettyItem):
-
- def __init__(self, width, indent):
- PrettyItem.__init__(self, width)
- self.indent = indent
- self.space = 0
- self.active = 0
-
- def output(self, out):
- out.write(' ' * self.width)
-
- def prettyprint(self, line):
- if line.breaks(self.space):
- self.active = 1
- line.newline(self.indent)
- else:
- line.output(self)
-
- def show(self, out):
- print >> out, ("(break (width %d) (indent %d) (space %d) (active %d))"
- % (self.width, self.indent, self.space, self.lspace, self.active))
-
-class PrettyNewline(PrettySpace):
-
- def __init__(self, indent):
- PrettySpace.__init__(self, indent)
-
- def insert(self, block):
- block.newline()
- block.addtoline(self)
-
- def output(self, out):
- out.write(' ' * self.width)
-
- def prettyprint(self, line):
- line.newline(0)
- line.output(self)
-
- def show(self, out):
- print >> out, ("(nl (indent %d))" % self.indent)
-
-class PrettyLine(PrettyItem):
- def __init__(self):
- PrettyItem.__init__(self, 0)
- self.content = []
-
- def write(self, x):
- self.content.append(x)
-
- def end(self):
- width = 0
- lastwidth = 0
- lastbreak = None
- for x in self.content:
- if isinstance(x, PrettyBreak):
- if lastbreak:
- lastbreak.space = (width - lastwidth)
- lastbreak = x
- lastwidth = width
- width += x.get_width()
- if lastbreak:
- lastbreak.space = (width - lastwidth)
- self.width = width
-
- def prettyprint(self, line):
- for x in self.content:
- x.prettyprint(line)
-
- def show(self, out):
- print >> out, '(LINE (width %d)' % self.width
- for x in self.content:
- x.show(out)
- print >> out, ')'
-
-class PrettyBlock(PrettyItem):
-
- def __init__(self, all=0, parent=None):
- self.width = 0
- self.lines = []
- self.parent = parent
- self.indent = 0
- self.all = all
- self.broken = 0
- self.newline()
-
- def add(self, item):
- item.insert(self)
-
- def end(self):
- self.width = 0
- for l in self.lines:
- l.end()
- if self.width < l.width:
- self.width = l.width
-
- def breaks(self, n):
- return self.all and self.broken
-
- def newline(self):
- self.lines.append(PrettyLine())
-
- def addtoline(self, x):
- self.lines[-1].write(x)
-
- def prettyprint(self, line):
- self.indent = line.used
- line.block = self
- if not line.fits(self.width):
- self.broken = 1
- for l in self.lines:
- l.prettyprint(line)
- line.block = self.parent
-
- def show(self, out):
- print >> out, ('(BLOCK (width %d) (indent %d) (all %d) (broken %d)' %
- (self.width, self.indent, self.all, self.broken))
- for l in self.lines:
- l.show(out)
- print >> out, ')'
-
-class Line:
-
- def __init__(self, out, width):
- self.out = out
- self.width = width
- self.used = 0
- self.space = self.width
-
- def newline(self, indent):
- indent += self.block.indent
- self.out.write('\n')
- self.out.write(' ' * indent)
- self.used = indent
- self.space = self.width - self.used
-
- def fits(self, n):
- return self.space - n >= 0
-
- def breaks(self, n):
- return self.block.breaks(n) or not self.fits(n)
-
- def output(self, x):
- n = x.get_width()
- self.space -= n
- self.used += n
- if self.space < 0:
- self.space = 0
- x.output(self.out)
-
-class PrettyPrinter:
- """A prettyprinter based on what I remember of Derek Oppen's
- prettyprint algorithm from TOPLAS way back.
- """
-
- def __init__(self, width=40):
- self.width = width
- self.block = None
- self.top = None
-
- def write(self, x):
- self.block.add(PrettyString(x))
-
- def add(self, item):
- self.block.add(item)
-
- def addbreak(self, width=1, indent=4):
- self.add(PrettyBreak(width, indent))
-
- def addspace(self, width=1):
- self.add(PrettySpace(width))
-
- def addnl(self, indent=0):
- self.add(PrettyNewline(indent))
-
- def begin(self, all=0):
- block = PrettyBlock(all=all, parent=self.block)
- self.block = block
-
- def end(self):
- self.block.end()
- if self.block.parent:
- self.block.parent.add(self.block)
- else:
- self.top = self.block
- self.block = self.block.parent
-
- def prettyprint(self, out=sys.stdout):
- line = Line(out, self.width)
- self.top.prettyprint(line)
-
-class SXPPrettyPrinter(PrettyPrinter):
- """An SXP prettyprinter.
- """
-
- def pstring(self, x):
- io = StringIO.StringIO()
- sxp.show(x, out=io)
- io.seek(0)
- val = io.getvalue()
- io.close()
- return val
-
- def pprint(self, l):
- if isinstance(l, types.ListType):
- self.begin(all=1)
- self.write('(')
- i = 0
- for x in l:
- if(i): self.addbreak()
- self.pprint(x)
- i += 1
- self.addbreak(width=0, indent=0)
- self.write(')')
- self.end()
- else:
- self.write(self.pstring(l))
-
-def prettyprint(sxpr, out=sys.stdout, width=80):
- """Prettyprint an SXP form.
-
- sxpr s-expression
- out destination
- width maximum output width
- """
- if isinstance(sxpr, types.ListType):
- pp = SXPPrettyPrinter(width=width)
- pp.pprint(sxpr)
- pp.prettyprint(out=out)
- else:
- sxp.show(sxpr, out=out)
- print >> out
-
-def main():
- pin = sxp.Parser()
- while 1:
- buf = sys.stdin.read(100)
- pin.input(buf)
- if buf == '': break
- l = pin.get_val()
- prettyprint(l, width=80)
-
-if __name__ == "__main__":
- main()
-
+++ /dev/null
-import os
-import os.path
-import sys
-
-VIFCTL = '/etc/xen/xend/vifctl'
-
-def init():
- os.system(VIFCTL + ' init ')
-
-def up(vif, mac=None, bridge=None, ipaddr=[]):
- args = ['vif=%s' % vif]
- if mac:
- args.append('mac=%s' % mac)
- if bridge:
- args.append('bridge=%s' % bridge)
- if ipaddr:
- args.append('ipaddr=%s' % ','.join(ipaddr))
- os.system(VIFCTL + ' up ' + ' '.join(args))
-
-def down(vif, mac=None, bridge=None, ipaddr=[]):
- args = ['vif=%s' % vif]
- if mac:
- args.append('mac=%s' % mac)
- if bridge:
- args.append('bridge=%s' % bridge)
- if ipaddr:
- args.append('ipaddr=%s' % ','.join(ipaddr))
- os.system(VIFCTL + ' down ' + ' '.join(args))
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-"""Client API for the HTTP interface on xend.
-Callable as a script - see main().
-"""
-import sys
-import httplib
-import types
-from StringIO import StringIO
-import urlparse
-
-from encode import *
-import sxp
-import PrettyPrint
-
-DEBUG = 0
-
-class Foo(httplib.HTTPResponse):
-
- def begin(self):
- fin = self.fp
- while(1):
- buf = fin.readline()
- print "***", buf
- if buf == '':
- print
- sys.exit()
-
-
-def sxprio(sxpr):
- io = StringIO()
- sxp.show(sxpr, out=io)
- print >> io
- io.seek(0)
- return io
-
-def fileof(val):
- """Converter for passing configs.
- Handles lists, files directly.
- Assumes a string is a file name and passes its contents.
- """
- if isinstance(val, types.ListType):
- return sxprio(val)
- if isinstance(val, types.StringType):
- return file(val)
- if hasattr(val, 'readlines'):
- return val
-
-# todo: need to sort of what urls/paths are using for objects.
-# e.g. for domains at the moment return '0'.
-# should probably return abs path w.r.t. server, e.g. /xend/domain/0.
-# As an arg, assume abs path is obj uri, otherwise just id.
-
-# Function to convert to full url: Xend.uri(path), e.g.
-# maps /xend/domain/0 to http://wray-m-3.hpl.hp.com:8000/xend/domain/0
-# And should accept urls for ids?
-
-def urljoin(location, root, prefix='', rest=''):
- prefix = str(prefix)
- rest = str(rest)
- base = 'http://' + location + root + prefix
- url = urlparse.urljoin(base, rest)
- return url
-
-def nodeurl(location, root, id=''):
- return urljoin(location, root, 'node/', id)
-
-def domainurl(location, root, id=''):
- return urljoin(location, root, 'domain/', id)
-
-def consoleurl(location, root, id=''):
- return urljoin(location, root, 'console/', id)
-
-def deviceurl(location, root, id=''):
- return urljoin(location, root, 'device/', id)
-
-def vneturl(location, root, id=''):
- return urljoin(location, root, 'vnet/', id)
-
-def eventurl(location, root, id=''):
- return urljoin(location, root, 'event/', id)
-
-def xend_request(url, method, data=None):
- urlinfo = urlparse.urlparse(url)
- (uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo
- if DEBUG: print url, urlinfo
- if uproto != 'http':
- raise StandardError('Invalid protocol: ' + uproto)
- if DEBUG: print '>xend_request', ulocation, upath, method, data
- (hdr, args) = encode_data(data)
- if data and method == 'GET':
- upath += '?' + args
- args = None
- if method == "POST" and upath.endswith('/'):
- upath = upath[:-1]
- if DEBUG: print "ulocation=", ulocation, "upath=", upath, "args=", args
- #hdr['User-Agent'] = 'Mozilla'
- #hdr['Accept'] = 'text/html,text/plain'
- conn = httplib.HTTPConnection(ulocation)
- #conn.response_class = Foo
- if DEBUG: conn.set_debuglevel(1)
- conn.request(method, upath, args, hdr)
- resp = conn.getresponse()
- if DEBUG: print resp.status, resp.reason
- if DEBUG: print resp.msg.headers
- if resp.status in [204, 404]:
- return None
- if resp.status not in [200, 201, 202, 203]:
- raise RuntimeError(resp.reason)
- pin = sxp.Parser()
- data = resp.read()
- if DEBUG: print "***data" , data
- if DEBUG: print "***"
- pin.input(data);
- pin.input_eof()
- conn.close()
- val = pin.get_val()
- #if isinstance(val, types.ListType) and sxp.name(val) == 'val':
- # val = val[1]
- if isinstance(val, types.ListType) and sxp.name(val) == 'err':
- raise RuntimeError(val[1])
- if DEBUG: print '**val='; sxp.show(val); print
- return val
-
-def xend_get(url, args=None):
- return xend_request(url, "GET", args)
-
-def xend_call(url, data):
- return xend_request(url, "POST", data)
-
-class Xend:
-
- SRV_DEFAULT = "localhost:8000"
- ROOT_DEFAULT = "/xend/"
-
- def __init__(self, srv=None, root=None):
- self.bind(srv, root)
-
- def bind(self, srv=None, root=None):
- if srv is None: srv = self.SRV_DEFAULT
- if root is None: root = self.ROOT_DEFAULT
- if not root.endswith('/'): root += '/'
- self.location = srv
- self.root = root
-
- def nodeurl(self, id=''):
- return nodeurl(self.location, self.root, id)
-
- def domainurl(self, id=''):
- return domainurl(self.location, self.root, id)
-
- def consoleurl(self, id=''):
- return consoleurl(self.location, self.root, id)
-
- def deviceurl(self, id=''):
- return deviceurl(self.location, self.root, id)
-
- def vneturl(self, id=''):
- return vneturl(self.location, self.root, id)
-
- def eventurl(self, id=''):
- return eventurl(self.location, self.root, id)
-
- def xend(self):
- return xend_get(urljoin(self.location, self.root))
-
- def xend_node(self):
- return xend_get(self.nodeurl())
-
- def xend_node_cpu_rrobin_slice_set(self, slice):
- return xend_call(self.nodeurl(),
- {'op' : 'cpu_rrobin_slice_set',
- 'slice' : slice })
-
- def xend_node_cpu_bvt_slice_set(self, slice):
- return xend_call(self.nodeurl(),
- {'op' : 'cpu_bvt_slice_set',
- 'slice' : slice })
-
- def xend_domains(self):
- return xend_get(self.domainurl())
-
- def xend_domain_create(self, conf):
- return xend_call(self.domainurl(),
- {'op' : 'create',
- 'config' : fileof(conf) })
-
- def xend_domain(self, id):
- return xend_get(self.domainurl(id))
-
- def xend_domain_unpause(self, id):
- return xend_call(self.domainurl(id),
- {'op' : 'unpause'})
-
- def xend_domain_pause(self, id):
- return xend_call(self.domainurl(id),
- {'op' : 'pause'})
-
- def xend_domain_shutdown(self, id):
- return xend_call(self.domainurl(id),
- {'op' : 'shutdown'})
-
- def xend_domain_destroy(self, id):
- return xend_call(self.domainurl(id),
- {'op' : 'destroy'})
-
- def xend_domain_save(self, id, filename):
- return xend_call(self.domainurl(id),
- {'op' : 'save',
- 'file' : filename})
-
- def xend_domain_restore(self, id, filename):
- return xend_call(self.domainurl(id),
- {'op' : 'restore',
- 'file' : filename })
-
- def xend_domain_migrate(self, id, dst):
- return xend_call(self.domainurl(id),
- {'op' : 'migrate',
- 'destination': dst})
-
- def xend_domain_pincpu(self, id, cpu):
- return xend_call(self.domainurl(id),
- {'op' : 'pincpu',
- 'cpu' : cpu})
-
- def xend_domain_cpu_bvt_set(self, id, mcuadv, warp, warpl, warpu):
- return xend_call(self.domainurl(id),
- {'op' : 'cpu_bvt_set',
- 'mcuadv' : mvuadv,
- 'warp' : warp,
- 'warpl' : warpl,
- 'warpu' : warpu })
-
- def xend_domain_cpu_atropos_set(self, id, period, slice, latency, xtratime):
- return xend_call(self.domainurl(id),
- {'op' : 'cpu_atropos_set',
- 'period' : period,
- 'slice' : slice,
- 'latency' : latency,
- 'xtratime': xtratime })
-
- def xend_domain_vifs(self, id):
- return xend_get(self.domainurl(id),
- { 'op' : 'vifs' })
-
- def xend_domain_vif_ip_add(self, id, vif, ipaddr):
- return xend_call(self.domainurl(id),
- {'op' : 'vif_ip_add',
- 'vif' : vif,
- 'ip' : ipaddr })
-
- def xend_domain_vbds(self, id):
- return xend_get(self.domainurl(id),
- {'op' : 'vbds'})
-
- def xend_domain_vbd(self, id, vbd):
- return xend_get(self.domainurl(id),
- {'op' : 'vbd',
- 'vbd' : vbd})
-
- def xend_consoles(self):
- return xend_get(self.consoleurl())
-
- def xend_console(self, id):
- return xend_get(self.consoleurl(id))
-
- def xend_vnets(self):
- return xend_get(self.vneturl())
-
- def xend_vnet_create(self, conf):
- return xend_call(self.vneturl(),
- {'op': 'create', 'config': fileof(conf) })
-
- def xend_vnet(self, id):
- return xend_get(self.vneturl(id))
-
- def xend_vnet_delete(self, id):
- return xend_call(self.vneturl(id),
- {'op': 'delete'})
-
- def xend_event_inject(self, sxpr):
- val = xend_call(self.eventurl(),
- {'op': 'inject', 'event': fileof(sxpr) })
-
-
-def main(argv):
- """Call an API function:
-
- python XendClient.py fn args...
-
- The leading 'xend_' on the function can be omitted.
- Example:
-
- > python XendClient.py domains
- (domain 0 8)
- > python XendClient.py domain 0
- (domain (id 0) (name Domain-0) (memory 128))
- """
- server = Xend()
- fn = argv[1]
- if not fn.startswith('xend'):
- fn = 'xend_' + fn
- args = argv[2:]
- val = getattr(server, fn)(*args)
- PrettyPrint.prettyprint(val)
- print
-
-if __name__ == "__main__":
- main(sys.argv)
-else:
- server = Xend()
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-import socket
-import xen.ext.xc
-xc = xen.ext.xc.new()
-
-import sxp
-import XendRoot
-xroot = XendRoot.instance()
-import XendDB
-
-import EventServer
-eserver = EventServer.instance()
-
-from xen.xend.server import SrvDaemon
-daemon = SrvDaemon.instance()
-
-class XendConsoleInfo:
- """Console information record.
- """
-
- def __init__(self, console, dom1, port1, dom2, port2, conn=None):
- self.console = console
- self.dom1 = int(dom1)
- self.port1 = int(port1)
- self.dom2 = int(dom2)
- self.port2 = int(port2)
- self.conn = conn
- #self.id = "%d.%d-%d.%d" % (self.dom1, self.port1, self.dom2, self.port2)
- self.id = str(port1)
-
- def __str__(self):
- s = "console"
- s += " id=%s" % self.id
- s += " src=%d.%d" % (self.dom1, self.port1)
- s += " dst=%d.%d" % (self.dom2, self.port2)
- s += " port=%s" % self.console
- if self.conn:
- s += " conn=%s:%s" % (self.conn[0], self.conn[1])
- return s
-
- def sxpr(self):
- sxpr = ['console',
- ['id', self.id],
- ['src', self.dom1, self.port1],
- ['dst', self.dom2, self.port2],
- ['port', self.console],
- ]
- if self.conn:
- sxpr.append(['connected', self.conn[0], self.conn[1]])
- return sxpr
-
- def connection(self):
- return self.conn
-
- def update(self, consinfo):
- conn = sxp.child(consinfo, 'connected')
- if conn:
- self.conn = conn[1:]
- else:
- self.conn = None
-
- def uri(self):
- """Get the uri to use to connect to the console.
- This will be a telnet: uri.
-
- return uri
- """
- host = socket.gethostname()
- return "telnet://%s:%s" % (host, self.console)
-
-class XendConsole:
-
- dbpath = "console"
-
- def __init__(self):
- self.db = XendDB.XendDB(self.dbpath)
- self.console = {}
- self.console_db = self.db.fetchall("")
- if xroot.get_rebooted():
- print 'XendConsole> rebooted: removing all console info'
- self.rm_all()
- eserver.subscribe('xend.domain.died', self.onDomainDied)
- eserver.subscribe('xend.domain.destroy', self.onDomainDied)
-
- def rm_all(self):
- """Remove all console info. Used after reboot.
- """
- for (k, v) in self.console_db.items():
- self._delete_console(k)
-
- def refresh(self):
- consoles = daemon.consoles()
- cons = {}
- for consinfo in consoles:
- id = str(sxp.child_value(consinfo, 'id'))
- cons[id] = consinfo
- if id not in self.console:
- self._new_console(consinfo)
- for c in self.console.values():
- consinfo = cons.get(c.id)
- if consinfo:
- c.update(consinfo)
- else:
- self._delete_console(c.id)
-
- def onDomainDied(self, event, val):
- dom = int(val)
- #print 'XendConsole>onDomainDied', 'event', event, "dom=", dom
- for c in self.consoles():
- #print 'onDomainDied', "dom=", dom, "dom1=", c.dom1, "dom2=", c.dom2
- if (c.dom1 == dom) or (c.dom2 == dom):
- 'XendConsole>onDomainDied', 'delete console dom=', dom
- ctrl = daemon.get_domain_console(dom)
- if ctrl:
- ctrl.close()
- self._delete_console(c.id)
-
- def sync(self):
- self.db.saveall("", self.console_db)
-
- def sync_console(self, id):
- self.db.save(id, self.console_db[id])
-
- def _new_console(self, consinfo):
- # todo: xen needs a call to get current domain id.
- dom1 = 0
- port1 = sxp.child_value(consinfo, 'local_port')
- dom2 = sxp.child_value(consinfo, 'domain')
- port2 = sxp.child_value(consinfo, 'remote_port')
- console = sxp.child_value(consinfo, 'console_port')
- info = XendConsoleInfo(console, dom1, int(port1), int(dom2), int(port2))
- info.update(consinfo)
- self._add_console(info.id, info)
- return info
-
- def _add_console(self, id, info):
- self.console[id] = info
- self.console_db[id] = info.sxpr()
- self.sync_console(id)
-
- def _delete_console(self, id):
- if id in self.console:
- del self.console[id]
- if id in self.console_db:
- del self.console_db[id]
- self.db.delete(id)
-
- def console_ls(self):
- self.refresh()
- return self.console.keys()
-
- def consoles(self):
- self.refresh()
- return self.console.values()
-
- def console_create(self, dom):
- consinfo = daemon.console_create(dom)
- info = self._new_console(consinfo)
- return info
-
- def console_get(self, id):
- self.refresh()
- return self.console.get(id)
-
- def console_delete(self, id):
- self._delete_console(id)
-
- def console_disconnect(self, id):
- id = int(id)
- daemon.console_disconnect(id)
-
-def instance():
- global inst
- try:
- inst
- except:
- inst = XendConsole()
- return inst
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-import os
-import os.path
-import errno
-import dircache
-import time
-
-import sxp
-import XendRoot
-xroot = XendRoot.instance()
-
-class XendDB:
- """Persistence for Xend. Stores data in files and directories.
- """
-
- def __init__(self, path=None):
- self.dbpath = xroot.get_dbroot()
- if path:
- self.dbpath = os.path.join(self.dbpath, path)
- pass
-
- def filepath(self, path):
- return os.path.join(self.dbpath, path)
-
- def fetch(self, path):
- fpath = self.filepath(path)
- return self.fetchfile(fpath)
-
- def fetchfile(self, fpath):
- pin = sxp.Parser()
- fin = file(fpath, "rb")
- try:
- while 1:
- try:
- buf = fin.read(1024)
- except IOError, ex:
- if ex.errno == errno.EINTR:
- continue
- else:
- raise
- pin.input(buf)
- if buf == '':
- pin.input_eof()
- break
- finally:
- fin.close()
- return pin.get_val()
-
- def save(self, path, sxpr):
- fpath = self.filepath(path)
- return self.savefile(fpath, sxpr)
-
- def savefile(self, fpath, sxpr):
- fdir = os.path.dirname(fpath)
- if not os.path.isdir(fdir):
- os.makedirs(fdir)
- fout = file(fpath, "wb+")
- try:
- t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
- fout.write("# %s %s\n" % (fpath, t))
- sxp.show(sxpr, out=fout)
- finally:
- fout.close()
-
- def fetchall(self, path):
- dpath = self.filepath(path)
- d = {}
- for k in dircache.listdir(dpath):
- try:
- v = self.fetchfile(os.path.join(dpath, k))
- d[k] = v
- except:
- pass
- return d
-
- def saveall(self, path, d):
- for (k, v) in d.items():
- self.save(os.path.join(path, k), v)
-
- def delete(self, path):
- dpath = self.filepath(path)
- os.unlink(dpath)
-
- def ls(self, path):
- dpath = self.filepath(path)
- return dircache.listdir(dpath)
-
-
-
-
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-"""Handler for domain operations.
- Nothing here is persistent (across reboots).
- Needs to be persistent for one uptime.
-"""
-import sys
-
-from twisted.internet import defer
-
-import xen.ext.xc; xc = xen.ext.xc.new()
-
-import sxp
-import XendRoot
-xroot = XendRoot.instance()
-import XendDB
-import XendDomainInfo
-import XendConsole
-import EventServer
-
-from xen.xend.server import SrvDaemon
-xend = SrvDaemon.instance()
-
-eserver = EventServer.instance()
-
-__all__ = [ "XendDomain" ]
-
-class XendDomain:
- """Index of all domains. Singleton.
- """
-
- dbpath = "domain"
- domain = {}
-
- def __init__(self):
- self.xconsole = XendConsole.instance()
- # Table of domain info indexed by domain id.
- self.db = XendDB.XendDB(self.dbpath)
- #self.domain = {}
- self.domain_db = self.db.fetchall("")
- if xroot.get_rebooted():
- print 'XendDomain> rebooted: removing all domain info'
- self.rm_all()
- eserver.subscribe('xend.virq', self.onVirq)
- self.initial_refresh()
-
- def onVirq(self, event, val):
- print 'XendDomain> virq', val
- self.reap()
-
- def rm_all(self):
- """Remove all domain info. Used after reboot.
- """
- for (k, v) in self.domain_db.items():
- self._delete_domain(k, notify=0)
-
- def initial_refresh(self):
- """Refresh initial domain info from domain_db.
- """
- print "initial_refresh>"
- for d in self.domain_db.values(): print 'db dom=', d
- domlist = xc.domain_getinfo()
- for d in domlist: print 'xc dom=', d
- doms = {}
- for d in domlist:
- domid = str(d['dom'])
- doms[domid] = d
- dlist = []
- for config in self.domain_db.values():
- domid = str(sxp.child_value(config, 'id'))
- print "dom=", domid, "config=", config
- if domid in doms:
- print "dom=", domid, "new"
- deferred = self._new_domain(config, doms[domid])
- dlist.append(deferred)
- else:
- print "dom=", domid, "del"
- self._delete_domain(domid)
- deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
- def cbok(val):
- #print "doms:"
- #for d in self.domain.values(): print 'dom', d
- self.refresh()
- print "XendDomain>initial_refresh> doms:"
- for d in self.domain.values(): print 'dom', d
- deferred.addCallback(cbok)
-
- def sync(self):
- """Sync domain db to disk.
- """
- self.db.saveall("", self.domain_db)
-
- def sync_domain(self, dom):
- """Sync info for a domain to disk.
-
- dom domain id (string)
- """
- self.db.save(dom, self.domain_db[dom])
-
- def close(self):
- pass
-
- def _new_domain(self, savedinfo, info):
- """Create a domain entry from saved info.
- """
-## console = None
-## kernel = None
-## id = sxp.child_value(info, 'id')
-## dom = int(id)
-## name = sxp.child_value(info, 'name')
-## memory = int(sxp.child_value(info, 'memory'))
-## consoleinfo = sxp.child(info, 'console')
-## if consoleinfo:
-## consoleid = sxp.child_value(consoleinfo, 'id')
-## console = self.xconsole.console_get(consoleid)
-## if dom and console is None:
-## # Try to connect a console.
-## console = self.xconsole.console_create(dom)
-## config = sxp.child(info, 'config')
-## if config:
-## image = sxp.child(info, 'image')
-## if image:
-## image = sxp.child0(image)
-## kernel = sxp.child_value(image, 'kernel')
-## dominfo = XendDomainInfo.XendDomainInfo(
-## config, dom, name, memory, kernel, console)
- config = sxp.child_value(savedinfo, 'config')
- deferred = XendDomainInfo.vm_recreate(config, info)
- def fn(dominfo):
- self.domain[dominfo.id] = dominfo
- deferred.addCallback(fn)
- return deferred
-
- def _add_domain(self, id, info, notify=1):
- self.domain[id] = info
- self.domain_db[id] = info.sxpr()
- self.sync_domain(id)
- if notify: eserver.inject('xend.domain.created', id)
-
- def _delete_domain(self, id, notify=1):
- if id in self.domain:
- if notify: eserver.inject('xend.domain.died', id)
- del self.domain[id]
- if id in self.domain_db:
- del self.domain_db[id]
- self.db.delete(id)
-
- def reap(self):
- """Go through the domains looking for ones that have crashed or stopped.
- Tidy them up.
- """
- print 'XendDomain>reap>'
- domlist = xc.domain_getinfo()
- casualties = []
- for d in domlist:
- #print 'dom', d
- dead = 0
- dead = dead or (d['crashed'] or d['shutdown'])
- dead = dead or (d['dying'] and
- not(d['running'] or d['paused'] or d['blocked']))
- if dead:
- casualties.append(d)
- for d in casualties:
- id = str(d['dom'])
- print 'XendDomain>reap> died id=', id, d
- dominfo = self.domain.get(id)
- if not dominfo: continue
- dominfo.died()
- self.domain_destroy(id, refresh=0)
- print 'XendDomain>reap<'
-
- def refresh(self):
- """Refresh domain list from Xen.
- """
- domlist = xc.domain_getinfo()
- # Index the domlist by id.
- # Add entries for any domains we don't know about.
- doms = {}
- for d in domlist:
- id = str(d['dom'])
- doms[id] = d
- if id not in self.domain:
- config = None
- #image = None
- #newinfo = XendDomainInfo.XendDomainInfo(
- # config, d['dom'], d['name'], d['mem_kb']/1024, image=image, info=d)
- deferred = XendDomainInfo.vm_recreate(config, d)
- def fn(dominfo):
- self._add_domain(dominfo.id, dominfo)
- deferred.addCallback(fn)
- # Remove entries for domains that no longer exist.
- for d in self.domain.values():
- dominfo = doms.get(d.id)
- if dominfo:
- d.update(dominfo)
- else:
- self._delete_domain(d.id)
- self.reap()
-
- def refresh_domain(self, id):
- dom = int(id)
- dominfo = xc.domain_getinfo(dom, 1)
- if dominfo == [] or dominfo[0]['dom'] != dom:
- try:
- self._delete_domain(id)
- except:
- print 'refresh_domain: error'
- raise
- pass
- else:
- d = self.domain.get(id)
- if d:
- d.update(dominfo[0])
-
- def domain_ls(self):
- # List domains.
- # Update info from kernel first.
- self.refresh()
- return self.domain.keys()
-
- def domains(self):
- self.refresh()
- return self.domain.values()
-
- def domain_create(self, config):
- # Create domain, log it.
- deferred = XendDomainInfo.vm_create(config)
- def fn(dominfo):
- self._add_domain(dominfo.id, dominfo)
- return dominfo
- deferred.addCallback(fn)
- return deferred
-
- def domain_get(self, id):
- id = str(id)
- self.refresh_domain(id)
- return self.domain.get(id)
-
- def domain_unpause(self, id):
- """(Re)start domain running.
- """
- dom = int(id)
- eserver.inject('xend.domain.unpause', id)
- return xc.domain_unpause(dom=dom)
-
- def domain_pause(self, id):
- """Pause domain execution.
- """
- dom = int(id)
- eserver.inject('xend.domain.pause', id)
- return xc.domain_pause(dom=dom)
-
- def domain_shutdown(self, id, reason='poweroff'):
- """Shutdown domain (nicely).
- """
- dom = int(id)
- if dom <= 0:
- return 0
- eserver.inject('xend.domain.shutdown', [id, reason])
- val = xend.domain_shutdown(dom, reason)
- self.refresh()
- return val
-
- def domain_destroy(self, id, refresh=1):
- """Terminate domain immediately.
- """
- dom = int(id)
- if dom <= 0:
- return 0
- eserver.inject('xend.domain.destroy', id)
- val = xc.domain_destroy(dom=dom)
- if refresh: self.refresh()
- return val
-
- def domain_migrate(self, id, dst):
- """Start domain migration.
- """
- # Need a cancel too?
- pass
-
- def domain_save(self, id, dst, progress=0):
- """Save domain state to file, destroy domain.
- """
- dom = int(id)
- dominfo = self.domain_get(id)
- if not dominfo:
- return -1
- vmconfig = sxp.to_string(dominfo.sxpr())
- self.domain_pause(id)
- eserver.inject('xend.domain.save', id)
- rc = xc.linux_save(dom=dom, state_file=dst, vmconfig=vmconfig, progress=progress)
- if rc == 0:
- self.domain_destroy(id)
- return rc
-
- def domain_restore(self, src, progress=0):
- """Restore domain from file.
- """
- dominfo = XendDomainInfo.vm_restore(src, progress=progress)
- self._add_domain(dominfo.id, dominfo)
- return dominfo
-
- #============================================================================
- # Backward compatibility stuff from here on.
-
- def domain_pincpu(self, dom, cpu):
- dom = int(dom)
- return xc.domain_pincpu(dom, cpu)
-
- def domain_cpu_bvt_set(self, dom, mcuadv, warp, warpl, warpu):
- dom = int(dom)
- return xc.bvtsched_domain_set(dom=dom, mcuadv=mcuadv,
- warp=warp, warpl=warpl, warpu=warpu)
-
- def domain_cpu_bvt_get(self, dom):
- dom = int(dom)
- return xc.bvtsched_domain_get(dom)
-
- def domain_cpu_atropos_set(self, dom, period, slice, latency, xtratime):
- dom = int(dom)
- return xc.atropos_domain_set(dom, period, slice, latency, xtratime)
-
- def domain_cpu_atropos_get(self, dom):
- dom = int(dom)
- return xc.atropos_domain_get(dom)
-
- def domain_vif_ls(self, dom):
- dominfo = self.domain_get(dom)
- if not dominfo: return None
- devs = dominfo.get_devices('vif')
- return range(0, len(devs))
-
- def domain_vif_get(self, dom, vif):
- dominfo = self.domain_get(dom)
- if not dominfo: return None
- return dominfo.get_device_by_index(vif)
-
-## def domain_vif_ip_add(self, dom, vif, ip):
-## dom = int(dom)
-## return xenctl.ip.setup_vfr_rules_for_vif(dom, vif, ip)
-
- def domain_vbd_ls(self, dom):
- dominfo = self.domain_get(dom)
- if not dominfo: return []
- devs = dominfo.get_devices('vbd')
- return [ sxp.child_value(v, 'dev') for v in devs ]
-
- def domain_vbd_get(self, dom, vbd):
- dominfo = self.domain_get(dom)
- if not dominfo: return None
- devs = dominfo.get_devices('vbd')
- for v in devs:
- if sxp.child_value(v, 'dev') == vbd:
- return v
- return None
-
- def domain_shadow_control(self, dom, op):
- dom = int(dom)
- return xc.shadow_control(dom, op)
-
- #============================================================================
-
-def instance():
- global inst
- try:
- inst
- except:
- inst = XendDomain()
- return inst
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-"""Handler for persistent domain configs.
-
-"""
-
-import sxp
-import XendDB
-import XendDomain
-
-__all__ = [ "XendDomainConfig" ]
-
-class XendDomainConfig:
-
- dbpath = 'config'
-
- def __init__(self):
- self.db = XendDB.XendDB(self.dbpath)
-
- def domain_config_ls(self, path):
- return self.db.ls(path)
-
- def domain_config_create(self, path, sxpr):
- self.db.save(path, sxpr)
- pass
-
- def domain_config_delete(self, path):
- self.db.delete(path)
-
- def domain_config_instance(self, path):
- """Create a domain from a config.
- """
- config = self.db.fetch(path)
- xd = XendDomain.instance()
- newdom = xd.domain_create(config)
- return newdom
-
-def instance():
- global inst
- try:
- inst
- except:
- inst = XendDomainConfig()
- return inst
+++ /dev/null
-#!/usr/bin/python
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-"""Representation of a single domain.
-Includes support for domain construction, using
-open-ended configurations.
-
-Author: Mike Wray <mike.wray@hpl.hp.com>
-
-"""
-
-import string
-import re
-import sys
-import os
-
-from twisted.internet import defer
-
-import xen.ext.xc; xc = xen.ext.xc.new()
-import xen.util.ip
-
-import sxp
-
-import XendConsole
-xendConsole = XendConsole.instance()
-
-import server.SrvDaemon
-xend = server.SrvDaemon.instance()
-
-SIF_BLK_BE_DOMAIN = (1<<4)
-SIF_NET_BE_DOMAIN = (1<<5)
-
-def readlines(fd):
- """Version of readlines safe against EINTR.
- """
- import errno
-
- lines = []
- while 1:
- try:
- line = fd.readline()
- except IOError, ex:
- if ex.errno == errno.EINTR:
- continue
- else:
- raise
- if line == '': break
- lines.append(line)
- return lines
-
-class VmError(ValueError):
- """Vm construction error."""
-
- def __init__(self, value):
- self.value = value
-
- def __str__(self):
- return self.value
-
-
-def blkdev_name_to_number(name):
- """Take the given textual block-device name (e.g., '/dev/sda1',
- 'hda') and return the device number used by the OS. """
-
- if not re.match( '/dev/', name ):
- name = '/dev/' + name
-
- return os.stat(name).st_rdev
-
-def lookup_raw_partn(partition):
- """Take the given block-device name (e.g., '/dev/sda1', 'hda')
- and return a dictionary { device, start_sector,
- nr_sectors, type }
- device: Device number of the given partition
- start_sector: Index of first sector of the partition
- nr_sectors: Number of sectors comprising this partition
- type: 'Disk' or identifying name for partition type
- """
-
- if not re.match( '/dev/', partition ):
- partition = '/dev/' + partition
-
- drive = re.split( '[0-9]', partition )[0]
-
- if drive == partition:
- fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' )
- line = readline(fd)
- if line:
- return [ { 'device' : blkdev_name_to_number(drive),
- 'start_sector' : long(0),
- 'nr_sectors' : long(line) * 2,
- 'type' : 'Disk' } ]
- return None
-
- # determine position on disk
- fd = os.popen( '/sbin/sfdisk -d ' + drive + ' 2>/dev/null' )
-
- #['/dev/sda3 : start= 16948575, size=16836120, Id=83, bootable\012']
- lines = readlines(fd)
- for line in lines:
- m = re.search( '^' + partition + '\s*: start=\s*([0-9]+), ' +
- 'size=\s*([0-9]+), Id=\s*(\S+).*$', line)
- if m:
- return [ { 'device' : blkdev_name_to_number(drive),
- 'start_sector' : long(m.group(1)),
- 'nr_sectors' : long(m.group(2)),
- 'type' : m.group(3) } ]
-
- return None
-
-def lookup_disk_uname(uname):
- """Lookup a list of segments for a physical device.
- uname [string]: name of the device in the format \'phy:dev\' for a physical device
- returns [list of dicts]: list of extents that make up the named device
- """
- ( type, d_name ) = string.split( uname, ':' )
-
- if type == "phy":
- segments = lookup_raw_partn( d_name )
- else:
- segments = None
- return segments
-
-def make_disk(dom, uname, dev, mode, recreate=0):
- """Create a virtual disk device for a domain.
-
- @returns Deferred
- """
- segments = lookup_disk_uname(uname)
- if not segments:
- raise VmError("vbd: Segments not found: uname=%s" % uname)
- if len(segments) > 1:
- raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname)
- segment = segments[0]
- vdev = blkdev_name_to_number(dev)
- ctrl = xend.blkif_create(dom, recreate=recreate)
-
- def fn(ctrl):
- return xend.blkif_dev_create(dom, vdev, mode, segment, recreate=recreate)
- ctrl.addCallback(fn)
- return ctrl
-
-def make_vif(dom, vif, vmac, recreate=0):
- """Create a virtual network device for a domain.
-
-
- @returns Deferred
- """
- xend.netif_create(dom, recreate=recreate)
- d = xend.netif_dev_create(dom, vif, vmac, recreate=recreate)
- return d
-
-def vif_up(iplist):
- """send an unsolicited ARP reply for all non link-local IP addresses.
-
- iplist IP addresses
- """
-
- IP_NONLOCAL_BIND = '/proc/sys/net/ipv4/ip_nonlocal_bind'
-
- def get_ip_nonlocal_bind():
- return int(open(IP_NONLOCAL_BIND, 'r').read()[0])
-
- def set_ip_nonlocal_bind(v):
- print >> open(IP_NONLOCAL_BIND, 'w'), str(v)
-
- def link_local(ip):
- return xen.util.ip.check_subnet(ip, '169.254.0.0', '255.255.0.0')
-
- def arping(ip, gw):
- cmd = '/usr/sbin/arping -A -b -I eth0 -c 1 -s %s %s' % (ip, gw)
- print cmd
- os.system(cmd)
-
- gateway = xen.util.ip.get_current_ipgw() or '255.255.255.255'
- nlb = get_ip_nonlocal_bind()
- if not nlb: set_ip_nonlocal_bind(1)
- try:
- for ip in iplist:
- if not link_local(ip):
- arping(ip, gateway)
- finally:
- if not nlb: set_ip_nonlocal_bind(0)
-
-config_handlers = {}
-
-def add_config_handler(name, h):
- """Add a handler for a config field.
-
- name field name
- h handler: fn(vm, config, field, index)
- """
- config_handlers[name] = h
-
-def get_config_handler(name):
- """Get a handler for a config field.
-
- returns handler or None
- """
- return config_handlers.get(name)
-
-"""Table of handlers for virtual machine images.
-Indexed by image type.
-"""
-image_handlers = {}
-
-def add_image_handler(name, h):
- """Add a handler for an image type
- name image type
- h handler: fn(config, name, memory, image)
- """
- image_handlers[name] = h
-
-def get_image_handler(name):
- """Get the handler for an image type.
- name image type
-
- returns handler or None
- """
- return image_handlers.get(name)
-
-"""Table of handlers for devices.
-Indexed by device type.
-"""
-device_handlers = {}
-
-def add_device_handler(name, h):
- """Add a handler for a device type.
-
- name device type
- h handler: fn(vm, dev)
- """
- device_handlers[name] = h
-
-def get_device_handler(name):
- """Get the handler for a device type.
-
- name device type
-
- returns handler or None
- """
- return device_handlers.get(name)
-
-def vm_create(config):
- """Create a VM from a configuration.
- If a vm has been partially created and there is an error it
- is destroyed.
-
- config configuration
-
- returns Deferred
- raises VmError for invalid configuration
- """
- print 'vm_create>'
- vm = XendDomainInfo()
- return vm.construct(config)
-
-def vm_recreate(config, info):
- """Create the VM object for an existing domain.
- """
- vm = XendDomainInfo()
- vm.recreate = 1
- vm.setdom(info['dom'])
- vm.name = info['name']
- vm.memory = info['mem_kb']/1024
- if config:
- d = vm.construct(config)
- else:
- d = defer.Deferred()
- d.callback(vm)
- return d
-
-def vm_restore(src, progress=0):
- """Restore a VM from a disk image.
-
- src saved state to restore
- progress progress reporting flag
- returns deferred
- raises VmError for invalid configuration
- """
- vm = XendDomainInfo()
- ostype = "linux" #todo Set from somewhere (store in the src?).
- restorefn = getattr(xc, "%s_restore" % ostype)
- d = restorefn(state_file=src, progress=progress)
- dom = int(d['dom'])
- if dom < 0:
- raise VMError('restore failed')
- vmconfig = sxp.from_string(d['vmconfig'])
- vm.config = sxp.child_value(vmconfig, 'config')
- deferred = vm.dom_configure(dom)
- def vifs_cb(val, vm):
- vif_up(vm.ipaddrs)
- deferred.addCallback(vifs_cb, vm)
- return deferred
-
-def dom_get(dom):
- domlist = xc.domain_getinfo(dom=dom)
- if domlist and dom == domlist[0]['dom']:
- return domlist[0]
- return None
-
-
-def append_deferred(dlist, v):
- if isinstance(v, defer.Deferred):
- dlist.append(v)
-
-def _vm_configure1(val, vm):
- d = vm.create_devices()
- print '_vm_configure1> made devices...'
- def cbok(x):
- print '_vm_configure1> cbok', x
- return x
- d.addCallback(cbok)
- d.addCallback(_vm_configure2, vm)
- print '_vm_configure1<'
- return d
-
-def _vm_configure2(val, vm):
- print '>callback _vm_configure2...'
- d = vm.configure_fields()
- def cbok(results):
- print '_vm_configure2> cbok', results
- return vm
- def cberr(err):
- print '_vm_configure2> cberr', err
- vm.destroy()
- return err
- d.addCallback(cbok)
- d.addErrback(cberr)
- print '<_vm_configure2'
- return d
-
-class XendDomainInfo:
- """Virtual machine object."""
-
- def __init__(self):
- self.recreate = 0
- self.config = None
- self.id = None
- self.dom = None
- self.name = None
- self.memory = None
- self.image = None
- self.ramdisk = None
- self.cmdline = None
- self.console = None
- self.devices = {}
- self.configs = []
- self.info = None
- self.ipaddrs = []
- self.blkif_backend = 0
- self.netif_backend = 0
- #todo: state: running, suspended
- self.state = 'running'
- #todo: set to migrate info if migrating
- self.migrate = None
-
- def setdom(self, dom):
- self.dom = int(dom)
- self.id = str(dom)
-
- def update(self, info):
- """Update with info from xc.domain_getinfo().
- """
- self.info = info
- self.memory = self.info['mem_kb'] / 1024
-
- def __str__(self):
- s = "domain"
- s += " id=" + self.id
- s += " name=" + self.name
- s += " memory=" + str(self.memory)
- if self.console:
- s += " console=" + self.console.id
- if self.image:
- s += " image=" + self.image
- s += ""
- return s
-
- __repr__ = __str__
-
- def sxpr(self):
- sxpr = ['domain',
- ['id', self.id],
- ['name', self.name],
- ['memory', self.memory] ]
- if self.info:
- run = (self.info['running'] and 'r') or '-'
- block = (self.info['blocked'] and 'b') or '-'
- stop = (self.info['paused'] and 'p') or '-'
- susp = (self.info['shutdown'] and 's') or '-'
- crash = (self.info['crashed'] and 'c') or '-'
- state = run + block + stop + susp + crash
- sxpr.append(['state', state])
- if self.info['shutdown']:
- reasons = ["poweroff", "reboot", "suspend"]
- reason = reasons[self.info['shutdown_reason']]
- sxpr.append(['shutdown_reason', reason])
- sxpr.append(['cpu', self.info['cpu']])
- sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
- if self.console:
- sxpr.append(self.console.sxpr())
- if self.config:
- sxpr.append(['config', self.config])
- return sxpr
-
- def construct(self, config):
- # todo - add support for scheduling params?
- self.config = config
- try:
- self.name = sxp.child_value(config, 'name')
- self.memory = int(sxp.child_value(config, 'memory', '128'))
- self.configure_backends()
- image = sxp.child_value(config, 'image')
- image_name = sxp.name(image)
- image_handler = get_image_handler(image_name)
- if image_handler is None:
- raise VmError('unknown image type: ' + image_name)
- image_handler(self, image)
- deferred = self.configure()
- except StandardError, ex:
- # Catch errors, cleanup and re-raise.
- self.destroy()
- raise
- def cbok(x):
- print 'vm_create> cbok', x
- return x
- deferred.addCallback(cbok)
- print 'vm_create<'
- return deferred
-
- def config_devices(self, name):
- """Get a list of the 'device' nodes of a given type from the config.
-
- name device type
- return list of device configs
- """
- devices = []
- for d in sxp.children(self.config, 'device'):
- dev = sxp.child0(d)
- if dev is None: continue
- if name == sxp.name(dev):
- devices.append(dev)
- return devices
-
- def add_device(self, type, dev):
- """Add a device to a virtual machine.
-
- dev device to add
- """
- dl = self.devices.get(type, [])
- dl.append(dev)
- self.devices[type] = dl
-
- def get_devices(self, type):
- val = self.devices.get(type, [])
- return val
-
- def get_device_by_id(self, type, id):
- """Get the device with the given id.
-
- id device id
-
- returns device or None
- """
- dl = self.get_devices(type)
- for d in dl:
- if d.getprop('id') == id:
- return d
- return None
-
- def get_device_by_index(self, type, idx):
- """Get the device with the given index.
-
- idx device index
-
- returns device or None
- """
- dl = self.get_devices(type)
- if 0 <= idx < len(dl):
- return dl[idx]
- else:
- return None
-
- def add_config(self, val):
- """Add configuration data to a virtual machine.
-
- val data to add
- """
- self.configs.append(val)
-
- def destroy(self):
- if self.dom <= 0:
- return 0
- return xc.domain_destroy(dom=self.dom)
-
- def died(self):
- print 'died>', self.dom
- self.release_devices()
-
- def release_devices(self):
- print 'release_devices>', self.dom
- self.release_vifs()
- self.release_vbds()
- self.devices = {}
-
- def release_vifs(self):
- print 'release_vifs>', self.dom
- if self.dom is None: return
- ctrl = xend.netif_get(self.dom)
- if ctrl:
- ctrl.destroy()
-
- def release_vbds(self):
- print 'release_vbds>', self.dom
- if self.dom is None: return
- ctrl = xend.blkif_get(self.dom)
- if ctrl:
- ctrl.destroy()
-
- def show(self):
- """Print virtual machine info.
- """
- print "[VM dom=%d name=%s memory=%d" % (self.dom, self.name, self.memory)
- print "image:"
- sxp.show(self.image)
- print
- for dl in self.devices:
- for dev in dl:
- print "device:"
- sxp.show(dev)
- print
- for val in self.configs:
- print "config:"
- sxp.show(val)
- print
- print "]"
-
- def init_domain(self):
- """Initialize the domain memory.
- """
- if self.recreate: return
- memory = self.memory
- name = self.name
- cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
- print 'init_domain>', memory, name, cpu
- dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu)
- if dom <= 0:
- raise VmError('Creating domain failed: name=%s memory=%d'
- % (name, memory))
- self.setdom(dom)
-
- def build_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n):
- """Build the domain boot image.
- """
- if self.recreate: return
- if len(cmdline) >= 256:
- print 'Warning: kernel cmdline too long'
- dom = self.dom
- buildfn = getattr(xc, '%s_build' % ostype)
- print 'build_domain>', ostype, dom, kernel, cmdline, ramdisk
- flags = 0
- if self.netif_backend: flags |= SIF_NET_BE_DOMAIN
- if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN
- err = buildfn(dom = dom,
- image = kernel,
- control_evtchn = self.console.port2,
- cmdline = cmdline,
- ramdisk = ramdisk,
- flags = flags)
- if err != 0:
- raise VmError('Building domain failed: type=%s dom=%d err=%d'
- % (ostype, dom, err))
-
- def create_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n):
- """Create a domain. Builds the image but does not configure it.
-
- ostype OS type
- kernel kernel image
- ramdisk kernel ramdisk
- cmdline kernel commandline
- vifs_n number of network interfaces
- """
- print 'create_domain>', ostype, kernel
- if not self.recreate:
- if not os.path.isfile(kernel):
- raise VmError('Kernel image does not exist: %s' % kernel)
- if ramdisk and not os.path.isfile(ramdisk):
- raise VMError('Kernel ramdisk does not exist: %s' % ramdisk)
- print 'create-domain> init_domain...'
- self.init_domain()
- print 'create_domain>', 'dom=', self.dom
- self.console = xendConsole.console_create(self.dom)
- self.build_domain(ostype, kernel, ramdisk, cmdline, vifs_n)
- self.image = kernel
- self.ramdisk = ramdisk
- self.cmdline = cmdline
-
- def create_devices(self):
- """Create the devices for a vm.
-
- returns Deferred
- raises VmError for invalid devices
- """
- print '>create_devices'
- dlist = []
- devices = sxp.children(self.config, 'device')
- index = {}
- for d in devices:
- dev = sxp.child0(d)
- if dev is None:
- raise VmError('invalid device')
- dev_name = sxp.name(dev)
- dev_index = index.get(dev_name, 0)
- dev_handler = get_device_handler(dev_name)
- if dev_handler is None:
- raise VmError('unknown device type: ' + dev_name)
- v = dev_handler(self, dev, dev_index)
- append_deferred(dlist, v)
- index[dev_name] = dev_index + 1
- deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
- print '<create_devices'
- return deferred
-
- def configure_backends(self):
- """Set configuration flags if the vm is a backend for netif of blkif.
- """
- for c in sxp.children(self.config, 'backend'):
- name = sxp.name(sxp.child0(c))
- if name == 'blkif':
- self.blkif_backend = 1
- elif name == 'netif':
- self.netif_backend = 1
- else:
- raise VmError('invalid backend type:' + str(name))
-
- def create_backends(self):
- """Setup the netif and blkif backends.
- """
- if self.blkif_backend:
- xend.blkif_set_control_domain(self.dom, recreate=self.recreate)
- if self.netif_backend:
- xend.netif_set_control_domain(self.dom, recreate=self.recreate)
-
- def configure(self):
- """Configure a vm.
-
- vm virtual machine
- config configuration
-
- returns Deferred - calls callback with vm
- """
- if self.blkif_backend:
- d = defer.Deferred()
- d.callback(1)
- else:
- d = xend.blkif_create(self.dom, recreate=self.recreate)
- d.addCallback(_vm_configure1, self)
- return d
-
- def dom_configure(self, dom):
- """Configure a domain.
-
- dom domain id
- returns deferred
- """
- d = dom_get(dom)
- if not d:
- raise VMError("Domain not found: %d" % dom)
- try:
- self.setdom(dom)
- self.name = d['name']
- self.memory = d['memory']/1024
- deferred = self.configure()
- except StandardError, ex:
- self.destroy()
- raise
- return deferred
-
- def configure_fields(self):
- dlist = []
- index = {}
- for field in sxp.children(self.config):
- field_name = sxp.name(field)
- field_index = index.get(field_name, 0)
- field_handler = get_config_handler(field_name)
- # Ignore unknown fields. Warn?
- if field_handler:
- v = field_handler(self, self.config, field, field_index)
- append_deferred(dlist, v)
- index[field_name] = field_index + 1
- d = defer.DeferredList(dlist, fireOnOneErrback=1)
- return d
-
-
-def vm_image_linux(vm, image):
- """Create a VM for a linux image.
-
- name vm name
- memory vm memory
- image image config
-
- returns vm
- """
- kernel = sxp.child_value(image, "kernel")
- cmdline = ""
- ip = sxp.child_value(image, "ip", "dhcp")
- if ip:
- cmdline += " ip=" + ip
- root = sxp.child_value(image, "root")
- if root:
- cmdline += " root=" + root
- args = sxp.child_value(image, "args")
- if args:
- cmdline += " " + args
- ramdisk = sxp.child_value(image, "ramdisk", '')
- vifs = vm.config_devices("vif")
- vm.create_domain("linux", kernel, ramdisk, cmdline, len(vifs))
- return vm
-
-def vm_image_netbsd(vm, image):
- """Create a VM for a bsd image.
-
- name vm name
- memory vm memory
- image image config
-
- returns vm
- """
- #todo: Same as for linux. Is that right? If so can unify them.
- kernel = sxp.child_value(image, "kernel")
- cmdline = ""
- ip = sxp.child_value(image, "ip", "dhcp")
- if ip:
- cmdline += "ip=" + ip
- root = sxp.child_value(image, "root")
- if root:
- cmdline += "root=" + root
- args = sxp.child_value(image, "args")
- if args:
- cmdline += " " + args
- ramdisk = sxp.child_value(image, "ramdisk")
- vifs = vm.config_devices("vif")
- vm.create_domain("netbsd", kernel, ramdisk, cmdline, len(vifs))
- return vm
-
-
-def vm_dev_vif(vm, val, index):
- """Create a virtual network interface (vif).
-
- vm virtual machine
- val vif config
- index vif index
- """
- if vm.netif_backend:
- raise VmError('vif: vif in netif backend domain')
- vif = index #todo
- vmac = sxp.child_value(val, "mac")
- defer = make_vif(vm.dom, vif, vmac, vm.recreate)
- def fn(id):
- dev = xend.netif_dev(vm.dom, vif)
- devid = sxp.attribute(val, 'id')
- if devid:
- dev.setprop('id', devid)
- bridge = sxp.child_value(val, "bridge")
- dev.up(bridge)
- vm.add_device('vif', dev)
- print 'vm_dev_vif> created', dev
- return id
- defer.addCallback(fn)
- return defer
-
-def vm_dev_vbd(vm, val, index):
- """Create a virtual block device (vbd).
-
- vm virtual machine
- val vbd config
- index vbd index
- """
- if vm.blkif_backend:
- raise VmError('vbd: vbd in blkif backend domain')
- vdev = index
- uname = sxp.child_value(val, 'uname')
- if not uname:
- raise VMError('vbd: Missing uname')
- dev = sxp.child_value(val, 'dev')
- if not dev:
- raise VMError('vbd: Missing dev')
- mode = sxp.child_value(val, 'mode', 'r')
- defer = make_disk(vm.dom, uname, dev, mode, vm.recreate)
- def fn(vbd):
- dev = xend.blkif_dev(vm.dom, vdev)
- vm.add_device('vbd', dev)
- return vbd
- defer.addCallback(fn)
- return defer
-
-def parse_pci(val):
- if isinstance(val, StringType):
- radix = 10
- if val.startswith('0x') or val.startswith('0X'):
- radix = 16
- v = int(val, radix)
- else:
- v = val
- return v
-
-def vm_dev_pci(vm, val, index):
- bus = sxp.child_value(val, 'bus')
- if not bus:
- raise VMError('pci: Missing bus')
- dev = sxp.child_value(val, 'dev')
- if not dev:
- raise VMError('pci: Missing dev')
- func = sxp.child_value(val, 'func')
- if not func:
- raise VMError('pci: Missing func')
- try:
- bus = parse_pci(bus)
- dev = parse_pci(dev)
- func = parse_pci(func)
- except:
- raise VMError('pci: invalid parameter')
- rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev,
- func=func, enable=1)
- if rc < 0:
- #todo non-fatal
- raise VMError('pci: Failed to configure device: bus=%s dev=%s func=%s' %
- (bus, dev, func))
- return rc
-
-
-def vm_field_vfr(vm, config, val, index):
- """Handle a vfr field in a config.
-
- vm virtual machine
- config vm config
- val vfr field
- """
- # Get the rules and add them.
- # (vfr (vif (id foo) (ip x.x.x.x)) ... )
- list = sxp.children(val, 'vif')
- ipaddrs = []
- for v in list:
- id = sxp.child_value(v, 'id')
- if id is None:
- raise VmError('vfr: missing vif id')
- id = int(id)
- dev = vm.get_device_by_index('vif', id)
- if not dev:
- raise VmError('vfr: invalid vif id %d' % id)
- vif = sxp.child_value(dev, 'vif')
- ip = sxp.child_value(v, 'ip')
- if not ip:
- raise VmError('vfr: missing ip address')
- ipaddrs.append(ip);
- # todo: Configure the ipaddrs.
- vm.ipaddrs = ipaddrs
-
-def vnet_bridge(vnet, vmac, dom, idx):
- """Add the device for the vif to the bridge for its vnet.
- """
- vif = "vif%d.%d" % (dom, idx)
- try:
- cmd = "(vif.conn (vif %s) (vnet %s) (vmac %s))" % (vif, vnet, vmac)
- print "*** vnet_bridge>", cmd
- out = file("/proc/vnet/policy", "wb")
- out.write(cmd)
- err = out.close()
- print "vnet_bridge>", "err=", err
- except IOError, ex:
- print "vnet_bridge>", ex
-
-def vm_field_vnet(vm, config, val, index):
- """Handle a vnet field in a config.
-
- vm virtual machine
- config vm config
- val vnet field
- index index
- """
- # Get the vif children. For each vif look up the vif device
- # with the given id and configure its vnet.
- # (vnet (vif (id foo) (vnet 2) (mac x:x:x:x:x:x)) ... )
- vif_vnets = sxp.children(val, 'vif')
- for v in vif_vnets:
- id = sxp.child_value(v, 'id')
- if id is None:
- raise VmError('vnet: missing vif id')
- dev = vm.get_device_by_id('vif', id)
- #vnet = sxp.child_value(v, 'vnet', 1)
- #mac = sxp.child_value(dev, 'mac')
- #vif = sxp.child_value(dev, 'vif')
- #vnet_bridge(vnet, mac, vm.dom, 0)
- #vm.add_config([ 'vif.vnet', ['id', id], ['vnet', vnet], ['mac', mac]])
-
-# Register image handlers for linux and bsd.
-add_image_handler('linux', vm_image_linux)
-add_image_handler('netbsd', vm_image_netbsd)
-
-# Register device handlers for vifs and vbds.
-add_device_handler('vif', vm_dev_vif)
-add_device_handler('vbd', vm_dev_vbd)
-add_device_handler('pci', vm_dev_pci)
-
-# Register config handlers for vfr and vnet.
-add_config_handler('vfr', vm_field_vfr)
-add_config_handler('vnet', vm_field_vnet)
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-import sys
-import socket
-
-import sxp
-import XendDB
-import EventServer; eserver = EventServer.instance()
-
-class XendMigrateInfo:
-
- # states: begin, active, failed, succeeded?
-
- def __init__(self, id, dom, dst):
- self.id = id
- self.state = 'begin'
- self.src_host = socket.gethostname()
- self.src_dom = dom
- self.dst_host = dst
- self.dst_dom = None
-
- def set_state(self, state):
- self.state = state
-
- def get_state(self):
- return self.state
-
- def sxpr(self):
- sxpr = ['migrate', ['id', self.id], ['state', self.state] ]
- sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ]
- sxpr.append(sxpr_src)
- sxpr_dst = ['dst', ['host', self.dst] ]
- if self.dst_dom:
- sxpr_dst.append(['domain', self.dst_dom])
- sxpr.append(sxpr_dst)
- return sxpr
-
-
-class XendMigrate:
- # Represents migration in progress.
- # Use log for indications of begin/end/errors?
- # Need logging of: domain create/halt, migrate begin/end/fail
- # Log via event server?
-
- dbpath = "migrate"
-
- def __init__(self):
- self.db = XendDB.XendDB(self.dbpath)
- self.migrate = {}
- self.migrate_db = self.db.fetchall("")
- self.id = 0
-
- def nextid(self):
- self.id += 1
- return "%d" % self.id
-
- def sync(self):
- self.db.saveall("", self.migrate_db)
-
- def sync_migrate(self, id):
- self.db.save(id, self.migrate_db[id])
-
- def close(self):
- pass
-
- def _add_migrate(self, id, info):
- self.migrate[id] = info
- self.migrate_db[id] = info.sxpr()
- self.sync_migrate(id)
- #eserver.inject('xend.migrate.begin', info.sxpr())
-
- def _delete_migrate(self, id):
- #eserver.inject('xend.migrate.end', id)
- del self.migrate[id]
- del self.migrate_db[id]
- self.db.delete(id)
-
- def migrate_ls(self):
- return self.migrate.keys()
-
- def migrates(self):
- return self.migrate.values()
-
- def migrate_get(self, id):
- return self.migrate.get(id)
-
- def migrate_begin(self, dom, dst):
- # Check dom for existence, not migrating already.
- # Create migrate info, tell xend to migrate it?
- # - or fork migrate command ourselves?
- # Subscribe to migrate notifications (for updating).
- id = self.nextid()
- info = XenMigrateInfo(id, dom, dst)
- self._add_migrate(id, info)
- return id
-
-def instance():
- global inst
- try:
- inst
- except:
- inst = XendMigrate()
- return inst
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-"""Handler for node operations.
- Has some persistent state:
- - logs
- - notification urls
-
-"""
-
-import os
-import xen.ext.xc
-
-class XendNode:
-
- def __init__(self):
- self.xc = xen.ext.xc.new()
-
- def shutdown(self):
- return 0
-
- def reboot(self):
- return 0
-
- def notify(self, uri):
- return 0
-
- def cpu_bvt_slice_set(self, slice):
- ret = 0
- #ret = self.xc.bvtsched_global_set(ctx_allow=slice)
- return ret
-
- def cpu_bvt_slice_get(self, slice):
- ret = 0
- #ret = self.xc.bvtsched_global_get()
- return ret
-
- def cpu_rrobin_slice_set(self, slice):
- ret = 0
- #ret = self.xc.rrobin_global_set(slice)
- return ret
-
- def info(self):
- return self.nodeinfo() + self.physinfo()
-
- def nodeinfo(self):
- (sys, host, rel, ver, mch) = os.uname()
- return [['system', sys],
- ['host', host],
- ['release', rel],
- ['version', ver],
- ['machine', mch]]
-
- def physinfo(self):
- pinfo = self.xc.physinfo()
- info = [['cores', pinfo['cores']],
- ['hyperthreads_per_core', pinfo['ht_per_core']],
- ['cpu_mhz', pinfo['cpu_khz']/1000],
- ['memory', pinfo['total_pages']/256],
- ['free_memory', pinfo['free_pages']/256]]
- return info
-
-
-
-def instance():
- global inst
- try:
- inst
- except:
- inst = XendNode()
- return inst
-
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-"""Xend root class.
-Creates the event server and handles configuration.
-"""
-
-import os
-import os.path
-import sys
-import EventServer
-
-# Initial create of the event server.
-eserver = EventServer.instance()
-
-import sxp
-
-def reboots():
- """Get a list of system reboots from wtmp.
- """
- out = os.popen('/usr/bin/last reboot', 'r')
- list = [ x.strip() for x in out if x.startswith('reboot') ]
- return list
-
-def last_reboot():
- """Get the last known system reboot.
- """
- l = reboots()
- return (l and l[-1]) or None
-
-class XendRoot:
- """Root of the management classes."""
-
- lastboot_default = "/var/xen/lastboot"
-
- """Default path to the root of the database."""
- dbroot_default = "/var/xen/xend-db"
-
- """Default path to the config file."""
- config_default = "/etc/xen/xend-config.sxp"
-
- """Environment variable used to override config_default."""
- config_var = "XEND_CONFIG"
-
- def __init__(self):
- self.rebooted = 0
- self.last_reboot = None
- self.dbroot = None
- self.config_path = None
- self.config = None
- self.configure()
- self.check_lastboot()
- eserver.subscribe('xend.*', self.event_handler)
- #eserver.subscribe('xend.domain.created', self.event_handler)
- #eserver.subscribe('xend.domain.died', self.event_handler)
-
- def start(self):
- eserver.inject('xend.start', self.rebooted)
-
- def event_handler(self, event, val):
- print >> sys.stderr, "EVENT>", event, val
-
- def read_lastboot(self):
- try:
- val = file(self.lastboot, 'rb').readlines()[0]
- except StandardError, ex:
- print 'warning: Error reading', self.lastboot, ex
- val = None
- return val
-
- def write_lastboot(self, val):
- if not val: return
- try:
- fdir = os.path.dirname(self.lastboot)
- if not os.path.isdir(fdir):
- os.makedirs(fdir)
- out = file(self.lastboot, 'wb+')
- out.write(val)
- out.close()
- except IOError, ex:
- print 'warning: Error writing', self.lastboot, ex
- pass
-
- def check_lastboot(self):
- """Check if there has been a system reboot since we saved lastboot.
- """
- last_val = self.read_lastboot()
- this_val = last_reboot()
- if this_val == last_val:
- self.rebooted = 0
- else:
- self.rebooted = 1
- self.write_lastboot(this_val)
- self.last_reboot = this_val
-
- def get_last_reboot(self):
- return self.last_reboot
-
- def get_rebooted(self):
- return self.rebooted
-
- def configure(self):
- self.set_config()
- self.dbroot = self.get_config_value("dbroot", self.dbroot_default)
- self.lastboot = self.get_config_value("lastboot", self.lastboot_default)
-
- def get_dbroot(self):
- """Get the path to the database root.
- """
- return self.dbroot
-
- def set_config(self):
- """If the config file exists, read it. If not, ignore it.
-
- The config file is a sequence of sxp forms.
- """
- self.config_path = os.getenv(self.config_var, self.config_default)
- if os.path.exists(self.config_path):
- fin = file(self.config_path, 'rb')
- try:
- config = sxp.parse(fin)
- config.insert(0, 'config')
- self.config = config
- finally:
- fin.close()
- else:
- self.config = ['config']
-
- def get_config(self, name=None):
- """Get the configuration element with the given name, or
- the whole configuration if no name is given.
-
- name element name (optional)
- returns config or none
- """
- if name is None:
- val = self.config
- else:
- val = sxp.child(self.config, name)
- return val
-
- def get_config_value(self, name, val=None):
- """Get the value of an atomic configuration element.
-
- name element name
- val default value (optional, defaults to None)
- returns value
- """
- return sxp.child_value(self.config, name, val=val)
-
-def instance():
- global inst
- try:
- inst
- except:
- inst = XendRoot()
- return inst
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-"""Handler for vnet operations.
-"""
-
-import sxp
-import XendDB
-
-class XendVnet:
- """Index of all vnets. Singleton.
- """
-
- dbpath = "vnet"
-
- def __init__(self):
- # Table of vnet info indexed by vnet id.
- self.vnet = {}
- self.db = XendDB.XendDB(self.dbpath)
- self.vnet = self.db.fetchall("")
-
- def vnet_ls(self):
- """List all vnets.
- """
- return self.vnet.keys()
-
- def vnets(self):
- return self.vnet.values()
-
- def vnet_get(self, id):
- """Get a vnet.
-
- id vnet id
- """
- return self.vnet.get(id)
-
- def vnet_create(self, info):
- """Create a vnet.
-
- info config
- """
- self.vnet_configure(info)
-
- def vnet_configure(self, info):
- """Configure a vnet.
- id vnet id
- info config
- """
- # Need to configure for real.
- # Only sync if succeeded - otherwise need to back out.
- self.vnet[info.id] = info
- self.db.save(info.id, info)
-
- def vnet_delete(self, id):
- """Delete a vnet.
-
- id vnet id
- """
- # Need to delete for real. What if fails?
- if id in self.vnet:
- del self.vnet[id]
- self.db.delete(id)
-
-def instance():
- global inst
- try:
- inst
- except:
- inst = XendVnet()
- return inst
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-"""Encoding for arguments to HTTP calls.
- Uses the url-encoding with MIME type 'application/x-www-form-urlencoded'
- if the data does not include files. Otherwise it uses the encoding with
- MIME type 'multipart/form-data'. See the HTML4 spec for details.
-
- """
-import sys
-import types
-from StringIO import StringIO
-
-import urllib
-import httplib
-import random
-import md5
-
-# Extract from HTML4 spec.
-## The following example illustrates "multipart/form-data"
-## encoding. Suppose we have the following form:
-
-## <FORM action="http://server.com/cgi/handle"
-## enctype="multipart/form-data"
-## method="post">
-## <P>
-## What is your name? <INPUT type="text" name="submit-name"><BR>
-## What files are you sending? <INPUT type="file" name="files"><BR>
-## <INPUT type="submit" value="Send"> <INPUT type="reset">
-## </FORM>
-
-## If the user enters "Larry" in the text input, and selects the text
-## file "file1.txt", the user agent might send back the following data:
-
-## Content-Type: multipart/form-data; boundary=AaB03x
-
-## --AaB03x
-## Content-Disposition: form-data; name="submit-name"
-
-## Larry
-## --AaB03x
-## Content-Disposition: form-data; name="files"; filename="file1.txt"
-## Content-Type: text/plain
-
-## ... contents of file1.txt ...
-## --AaB03x--
-
-## If the user selected a second (image) file "file2.gif", the user agent
-## might construct the parts as follows:
-
-## Content-Type: multipart/form-data; boundary=AaB03x
-
-## --AaB03x
-## Content-Disposition: form-data; name="submit-name"
-
-## Larry
-## --AaB03x
-## Content-Disposition: form-data; name="files"
-## Content-Type: multipart/mixed; boundary=BbC04y
-
-## --BbC04y
-## Content-Disposition: file; filename="file1.txt"
-## Content-Type: text/plain
-
-## ... contents of file1.txt ...
-## --BbC04y
-## Content-Disposition: file; filename="file2.gif"
-## Content-Type: image/gif
-## Content-Transfer-Encoding: binary
-
-## ...contents of file2.gif...
-## --BbC04y--
-## --AaB03x--
-
-__all__ = ['encode_data', 'encode_multipart', 'encode_form', 'mime_boundary' ]
-
-def data_values(d):
- if isinstance(d, types.DictType):
- return d.items()
- else:
- return d
-
-def encode_data(d):
- """Encode some data for HTTP transport.
- The encoding used is stored in 'Content-Type' in the headers.
-
- d data - sequence of tuples or dictionary
- returns a 2-tuple of the headers and the encoded data
- """
- val = ({}, None)
- if d is None: return val
- multipart = 0
- for (k, v) in data_values(d):
- if encode_isfile(v):
- multipart = 1
- break
- if multipart:
- val = encode_multipart(d)
- else:
- val = encode_form(d)
- return val
-
-def encode_isfile(v):
- if isinstance(v, types.FileType):
- return 1
- if hasattr(v, 'readlines'):
- return 1
- return 0
-
-def encode_multipart(d):
- boundary = mime_boundary()
- hdr = { 'Content-Type': 'multipart/form-data; boundary=' + boundary }
- out = StringIO()
- for (k,v) in data_values(d):
- out.write('--')
- out.write(boundary)
- out.write('\r\n')
- if encode_isfile(v):
- out.write('Content-Disposition: form-data; name="')
- out.write(k)
- if hasattr(v, 'name'):
- out.write('"; filename="')
- out.write(v.name)
- out.write('"\r\n')
- out.write('Content-Type: application/octet-stream\r\n')
- out.write('\r\n')
- for l in v.readlines():
- out.write(l)
- else:
- out.write('Content-Disposition: form-data; name="')
- out.write(k)
- out.write('"\r\n')
- out.write('\r\n')
- out.write(str(v))
- out.write('\r\n')
- out.write('--')
- out.write(boundary)
- out.write('--')
- out.write('\r\n')
- return (hdr, out.getvalue())
-
-def mime_boundary():
- random.seed()
- m = md5.new()
- for i in range(0, 10):
- c = chr(random.randint(1, 255))
- m.update(c)
- b = m.hexdigest()
- return b[0:16]
-
-def encode_form(d):
- hdr = { 'Content-Type': 'application/x-www-form-urlencoded' }
- val = urllib.urlencode(d)
- return (hdr, val)
-
-def main():
- #d = {'a': 1, 'b': 'x y', 'c': file('conf.sxp') }
- #d = {'a': 1, 'b': 'x y' }
- d = [ ('a', 1), ('b', 'x y'), ('c', file('conf.sxp')) ]
- #d = [ ('a', 1), ('b', 'x y')]
- v = encode_data(d)
- print v[0]
- sys.stdout.write(v[1])
- print
-
-if __name__ == "__main__":
- main()
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-import cgi
-
-import os
-import sys
-import types
-import StringIO
-
-from twisted.internet import defer
-from twisted.internet import reactor
-from twisted.web import error
-from twisted.web import resource
-from twisted.web import server
-
-from xen.xend import sxp
-from xen.xend import PrettyPrint
-
-def uri_pathlist(p):
- """Split a path into a list.
- p path
- return list of path elements
- """
- l = []
- for x in p.split('/'):
- if x == '': continue
- l.append(x)
- return l
-
-class SrvBase(resource.Resource):
- """Base class for services.
- """
-
- def parse_form(self, req, method):
- """Parse the data for a request, GET using the URL, POST using encoded data.
- Posts should use enctype='multipart/form-data' in the <form> tag,
- rather than 'application/x-www-form-urlencoded'. Only 'multipart/form-data'
- handles file upload.
-
- req request
- returns a cgi.FieldStorage instance
- """
- env = {}
- env['REQUEST_METHOD'] = method
- if self.query:
- env['QUERY_STRING'] = self.query
- val = cgi.FieldStorage(fp=req.rfile, headers=req.headers, environ=env)
- return val
-
- def use_sxp(self, req):
- """Determine whether to send an SXP response to a request.
- Uses SXP if there is no User-Agent, no Accept, or application/sxp is in Accept.
-
- req request
- returns 1 for SXP, 0 otherwise
- """
- ok = 0
- user_agent = req.getHeader('User-Agent')
- accept = req.getHeader('Accept')
- if (not user_agent) or (not accept) or (accept.find(sxp.mime_type) >= 0):
- ok = 1
- return ok
-
- def get_op_method(self, op):
- """Get the method for an operation.
- For operation 'foo' looks for 'op_foo'.
-
- op operation name
- returns method or None
- """
- op_method_name = 'op_' + op
- return getattr(self, op_method_name, None)
-
- def perform(self, req):
- """General operation handler for posted operations.
- For operation 'foo' looks for a method op_foo and calls
- it with op_foo(op, req). Replies with code 500 if op_foo
- is not found.
-
- The method must return a list when req.use_sxp is true
- and an HTML string otherwise (or list).
- Methods may also return a Deferred (for incomplete processing).
-
- req request
- """
- op = req.args.get('op')
- if op is None or len(op) != 1:
- req.setResponseCode(404, "Invalid")
- return ''
- op = op[0]
- op_method = self.get_op_method(op)
- if op_method is None:
- req.setResponseCode(501, "Not implemented")
- req.setHeader("Content-Type", "text/plain")
- req.write("Not implemented: " + op)
- return ''
- else:
- val = op_method(op, req)
- if isinstance(val, defer.Deferred):
- val.addCallback(self._cb_perform, req, 1)
- return server.NOT_DONE_YET
- else:
- self._cb_perform(val, req, 0)
- return ''
-
- def _cb_perform(self, val, req, dfr):
- """Callback to complete the request.
- May be called from a Deferred.
- """
- if isinstance(val, error.ErrorPage):
- req.write(val.render(req))
- elif self.use_sxp(req):
- req.setHeader("Content-Type", sxp.mime_type)
- sxp.show(val, req)
- else:
- req.write('<html><head></head><body>')
- self.print_path(req)
- if isinstance(val, types.ListType):
- req.write('<code><pre>')
- PrettyPrint.prettyprint(val, out=req)
- req.write('</pre></code>')
- else:
- req.write(str(val))
- req.write('</body></html>')
- if dfr:
- req.finish()
-
- def print_path(self, req):
- """Print the path with hyperlinks.
- """
- pathlist = [x for x in req.prepath if x != '' ]
- s = "/"
- req.write('<h1><a href="/">/</a>')
- for x in pathlist:
- s += x + "/"
- req.write(' <a href="%s">%s</a>/' % (s, x))
- req.write("</h1>")
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-from xen.xend import sxp
-from xen.xend import XendConsole
-from SrvDir import SrvDir
-
-class SrvConsole(SrvDir):
- """An individual console.
- """
-
- def __init__(self, info):
- SrvDir.__init__(self)
- self.info = info
- self.xc = XendConsole.instance()
-
- def op_disconnect(self, op, req):
- val = self.xc.console_disconnect(self.info.id)
- return val
-
- def render_POST(self, req):
- return self.perform(req)
-
- def render_GET(self, req):
- if self.use_sxp(req):
- req.setHeader("Content-Type", sxp.mime_type)
- sxp.show(self.info.sxpr(), out=req)
- else:
- req.write('<html><head></head><body>')
- self.print_path(req)
- #self.ls()
- req.write('<p>%s</p>' % self.info)
- req.write('<p><a href="%s">Connect to domain %d</a></p>'
- % (self.info.uri(), self.info.dom2))
- self.form(req)
- req.write('</body></html>')
- return ''
-
- def form(self, req):
- req.write('<form method="post" action="%s">' % req.prePathURL())
- if self.info.connection():
- req.write('<input type="submit" name="op" value="disconnect">')
- req.write('</form>')
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-from SrvDir import SrvDir
-from SrvConsole import SrvConsole
-from xen.xend import XendConsole
-from xen.xend import sxp
-
-class SrvConsoleDir(SrvDir):
- """Console directory.
- """
-
- def __init__(self):
- SrvDir.__init__(self)
- self.xconsole = XendConsole.instance()
-
- def console(self, x):
- val = None
- try:
- info = self.xconsole.console_get(x)
- val = SrvConsole(info)
- except KeyError, ex:
- print 'SrvConsoleDir>', ex
- pass
- return val
-
- def get(self, x):
- v = SrvDir.get(self, x)
- if v is not None:
- return v
- v = self.console(x)
- return v
-
- def render_GET(self, req):
- if self.use_sxp(req):
- req.setHeader("Content-Type", sxp.mime_type)
- self.ls_console(req, 1)
- else:
- req.write("<html><head></head><body>")
- self.print_path(req)
- self.ls(req)
- self.ls_console(req)
- #self.form(req.wfile)
- req.write("</body></html>")
- return ''
-
- def ls_console(self, req, use_sxp=0):
- url = req.prePathURL()
- if not url.endswith('/'):
- url += '/'
- if use_sxp:
- consoles = self.xconsole.console_ls()
- sxp.show(consoles, out=req)
- else:
- consoles = self.xconsole.consoles()
- consoles.sort(lambda x, y: cmp(x.id, y.id))
- req.write('<ul>')
- for c in consoles:
- req.write('<li><a href="%s%s"> %s</a></li>' % (url, c.id, c))
- req.write('</ul>')
+++ /dev/null
-###########################################################
-## Xen controller daemon
-## Copyright (c) 2004, K A Fraser (University of Cambridge)
-## Copyright (C) 2004, Mike Wray <mike.wray@hp.com>
-###########################################################
-
-import os
-import os.path
-import signal
-import sys
-import threading
-import linecache
-import socket
-import pwd
-import re
-import StringIO
-
-from twisted.internet import pollreactor
-pollreactor.install()
-
-from twisted.internet import reactor
-from twisted.internet import protocol
-from twisted.internet import abstract
-from twisted.internet import defer
-
-from xen.ext import xu
-
-from xen.xend import sxp
-from xen.xend import PrettyPrint
-from xen.xend import EventServer
-eserver = EventServer.instance()
-
-from xen.xend.server import SrvServer
-
-import channel
-import blkif
-import netif
-import console
-import domain
-from params import *
-
-DEBUG = 1
-
-class MgmtProtocol(protocol.DatagramProtocol):
- """Handler for the management socket (unix-domain).
- """
-
- def __init__(self, daemon):
- #protocol.DatagramProtocol.__init__(self)
- self.daemon = daemon
-
- def write(self, data, addr):
- return self.transport.write(data, addr)
-
- def datagramReceived(self, data, addr):
- if DEBUG: print 'datagramReceived> addr=', addr, 'data=', data
- io = StringIO.StringIO(data)
- try:
- vals = sxp.parse(io)
- res = self.dispatch(vals[0])
- self.send_result(addr, res)
- except SystemExit:
- raise
- except:
- if DEBUG:
- raise
- else:
- self.send_error(addr)
-
- def send_reply(self, addr, sxpr):
- io = StringIO.StringIO()
- sxp.show(sxpr, out=io)
- io.seek(0)
- self.write(io.getvalue(), addr)
-
- def send_result(self, addr, res):
-
- def fn(res, self=self, addr=addr):
- self.send_reply(addr, ['ok', res])
-
- if isinstance(res, defer.Deferred):
- res.addCallback(fn)
- else:
- fn(res)
-
- def send_error(self, addr):
- (extype, exval) = sys.exc_info()[:2]
- self.send_reply(addr, ['err',
- ['type', str(extype) ],
- ['value', str(exval) ] ] )
-
- def opname(self, name):
- """Get the name of the method for an operation.
- """
- return 'op_' + name.replace('.', '_')
-
- def operror(self, name, v):
- """Default operation handler - signals an error.
- """
- raise NotImplementedError('Invalid operation: ' +name)
-
- def dispatch(self, req):
- """Dispatch a request to its handler.
- """
- op_name = sxp.name(req)
- op_method_name = self.opname(op_name)
- op_method = getattr(self, op_method_name, self.operror)
- return op_method(op_name, req)
-
- def op_console_create(self, name, req):
- """Create a new control interface - console for a domain.
- """
- print name, req
- dom = sxp.child_value(req, 'domain')
- if not dom: raise ValueError('Missing domain')
- dom = int(dom)
- console_port = sxp.child_value(req, 'console_port')
- if console_port:
- console_port = int(console_port)
- resp = self.daemon.console_create(dom, console_port)
- print name, resp
- return resp
-
- def op_consoles(self, name, req):
- """Get a list of the consoles.
- """
- return self.daemon.consoles()
-
- def op_console_disconnect(self, name, req):
- id = sxp.child_value(req, 'id')
- if not id:
- raise ValueError('Missing console id')
- id = int(id)
- console = self.daemon.get_console(id)
- if not console:
- raise ValueError('Invalid console id')
- if console.conn:
- console.conn.loseConnection()
- return ['ok']
-
- def op_blkifs(self, name, req):
- pass
-
- def op_blkif_devs(self, name, req):
- pass
-
- def op_blkif_create(self, name, req):
- pass
-
- def op_blkif_dev_create(self, name, req):
- pass
-
- def op_netifs(self, name, req):
- pass
-
- def op_netif_devs(self, name, req):
- pass
-
- def op_netif_create(self, name, req):
- pass
-
- def op_netif_dev_create(self, name, req):
- pass
-
-class NotifierProtocol(protocol.Protocol):
- """Asynchronous handler for i/o on the notifier (event channel).
- """
-
- def __init__(self, channelFactory):
- self.channelFactory = channelFactory
-
- def notificationReceived(self, idx, type):
- #print 'NotifierProtocol>notificationReceived>', idx, type
- channel = self.channelFactory.getChannel(idx)
- if not channel:
- return
- #print 'NotifierProtocol>notificationReceived> channel', channel
- channel.notificationReceived(type)
-
- def connectionLost(self, reason=None):
- pass
-
- def doStart(self):
- pass
-
- def doStop(self):
- pass
-
- def startProtocol(self):
- pass
-
- def stopProtocol(self):
- pass
-
-class NotifierPort(abstract.FileDescriptor):
- """Transport class for the event channel.
- """
-
- def __init__(self, daemon, notifier, proto, reactor=None):
- assert isinstance(proto, NotifierProtocol)
- abstract.FileDescriptor.__init__(self, reactor)
- self.daemon = daemon
- self.notifier = notifier
- self.protocol = proto
-
- def startListening(self):
- self._bindNotifier()
- self._connectToProtocol()
-
- def stopListening(self):
- if self.connected:
- result = self.d = defer.Deferred()
- else:
- result = None
- self.loseConnection()
- return result
-
- def fileno(self):
- return self.notifier.fileno()
-
- def _bindNotifier(self):
- self.connected = 1
-
- def _connectToProtocol(self):
- self.protocol.makeConnection(self)
- self.startReading()
-
- def loseConnection(self):
- if self.connected:
- self.stopReading()
- self.disconnecting = 1
- reactor.callLater(0, self.connectionLost)
-
- def connectionLost(self, reason=None):
- abstract.FileDescriptor.connectionLost(self, reason)
- if hasattr(self, 'protocol'):
- self.protocol.doStop()
- self.connected = 0
- #self.notifier.close() # Not implemented.
- os.close(self.fileno())
- del self.notifier
- if hasattr(self, 'd'):
- self.d.callback(None)
- del self.d
-
- def doRead(self):
- #print 'NotifierPort>doRead>', self
- count = 0
- while 1:
- #print 'NotifierPort>doRead>', count
- notification = self.notifier.read()
- if not notification:
- break
- (idx, type) = notification
- self.protocol.notificationReceived(idx, type)
- self.notifier.unmask(idx)
- count += 1
- #print 'NotifierPort>doRead<'
-
-class EventProtocol(protocol.Protocol):
- """Asynchronous handler for a connected event socket.
- """
-
- def __init__(self, daemon):
- #protocol.Protocol.__init__(self)
- self.daemon = daemon
- # Event queue.
- self.queue = []
- # Subscribed events.
- self.events = []
- self.parser = sxp.Parser()
- self.pretty = 0
-
- # For debugging subscribe to everything and make output pretty.
- self.subscribe(['*'])
- self.pretty = 1
-
- def dataReceived(self, data):
- try:
- self.parser.input(data)
- if self.parser.ready():
- val = self.parser.get_val()
- res = self.dispatch(val)
- self.send_result(res)
- if self.parser.at_eof():
- self.loseConnection()
- except SystemExit:
- raise
- except:
- if DEBUG:
- raise
- else:
- self.send_error()
-
- def loseConnection(self):
- if self.transport:
- self.transport.loseConnection()
- if self.connected:
- reactor.callLater(0, self.connectionLost)
-
- def connectionLost(self, reason=None):
- self.unsubscribe()
-
- def send_reply(self, sxpr):
- io = StringIO.StringIO()
- if self.pretty:
- PrettyPrint.prettyprint(sxpr, out=io)
- else:
- sxp.show(sxpr, out=io)
- print >> io
- io.seek(0)
- return self.transport.write(io.getvalue())
-
- def send_result(self, res):
- return self.send_reply(['ok', res])
-
- def send_error(self):
- (extype, exval) = sys.exc_info()[:2]
- return self.send_reply(['err',
- ['type', str(extype)],
- ['value', str(exval)]])
-
- def send_event(self, val):
- return self.send_reply(['event', val[0], val[1]])
-
- def unsubscribe(self):
- for event in self.events:
- eserver.unsubscribe(event, self.queue_event)
-
- def subscribe(self, events):
- self.unsubscribe()
- for event in events:
- eserver.subscribe(event, self.queue_event)
- self.events = events
-
- def queue_event(self, name, v):
- # Despite the name we dont' queue the event here.
- # We send it because the transport will queue it.
- self.send_event([name, v])
-
- def opname(self, name):
- return 'op_' + name.replace('.', '_')
-
- def operror(self, name, req):
- raise NotImplementedError('Invalid operation: ' +name)
-
- def dispatch(self, req):
- op_name = sxp.name(req)
- op_method_name = self.opname(op_name)
- op_method = getattr(self, op_method_name, self.operror)
- return op_method(op_name, req)
-
- def op_help(self, name, req):
- def nameop(x):
- if x.startswith('op_'):
- return x[3:].replace('_', '.')
- else:
- return x
-
- l = [ nameop(k) for k in dir(self) if k.startswith('op_') ]
- return l
-
- def op_quit(self, name, req):
- self.loseConnection()
-
- def op_exit(self, name, req):
- sys.exit(0)
-
- def op_pretty(self, name, req):
- self.pretty = 1
- return ['ok']
-
- def op_console_disconnect(self, name, req):
- id = sxp.child_value(req, 'id')
- if not id:
- raise ValueError('Missing console id')
- self.daemon.console_disconnect(id)
- return ['ok']
-
- def op_info(self, name, req):
- val = ['info']
- val += self.daemon.consoles()
- val += self.daemon.blkifs()
- val += self.daemon.netifs()
- return val
-
- def op_sys_subscribe(self, name, v):
- # (sys.subscribe event*)
- # Subscribe to the events:
- self.subscribe(v[1:])
- return ['ok']
-
- def op_sys_inject(self, name, v):
- # (sys.inject event)
- event = v[1]
- eserver.inject(sxp.name(event), event)
- return ['ok']
-
-
-class EventFactory(protocol.Factory):
- """Asynchronous handler for the event server socket.
- """
- protocol = EventProtocol
- service = None
-
- def __init__(self, daemon):
- #protocol.Factory.__init__(self)
- self.daemon = daemon
-
- def buildProtocol(self, addr):
- proto = self.protocol(self.daemon)
- proto.factory = self
- return proto
-
-class VirqClient:
- def __init__(self, daemon):
- self.daemon = daemon
-
- def virqReceived(self, virq):
- print 'VirqClient.virqReceived>', virq
- eserver.inject('xend.virq', virq)
-
- def lostChannel(self, channel):
- print 'VirqClient.lostChannel>', channel
-
-class Daemon:
- """The xend daemon.
- """
- def __init__(self):
- self.shutdown = 0
-
- def daemon_pids(self):
- pids = []
- pidex = '(?P<pid>\d+)'
- pythonex = '(?P<python>\S*python\S*)'
- cmdex = '(?P<cmd>.*)'
- procre = re.compile('^\s*' + pidex + '\s*' + pythonex + '\s*' + cmdex + '$')
- xendre = re.compile('^/usr/sbin/xend\s*(start|restart)\s*.*$')
- procs = os.popen('ps -e -o pid,args 2>/dev/null')
- for proc in procs:
- pm = procre.match(proc)
- if not pm: continue
- xm = xendre.match(pm.group('cmd'))
- if not xm: continue
- #print 'pid=', pm.group('pid'), 'cmd=', pm.group('cmd')
- pids.append(int(pm.group('pid')))
- return pids
-
- def new_cleanup(self, kill=0):
- err = 0
- pids = self.daemon_pids()
- if kill:
- for pid in pids:
- print "Killing daemon pid=%d" % pid
- os.kill(pid, signal.SIGHUP)
- elif pids:
- err = 1
- print "Daemon already running: ", pids
- return err
-
- def cleanup(self, kill=False):
- # No cleanup to do if PID_FILE is empty.
- if not os.path.isfile(PID_FILE) or not os.path.getsize(PID_FILE):
- return 0
- # Read the pid of the previous invocation and search active process list.
- pid = open(PID_FILE, 'r').read()
- lines = os.popen('ps ' + pid + ' 2>/dev/null').readlines()
- for line in lines:
- if re.search('^ *' + pid + '.+xend', line):
- if not kill:
- print "Daemon is already running (pid %d)" % int(pid)
- return 1
- # Old daemon is still active: terminate it.
- os.kill(int(pid), 1)
- # Delete the stale PID_FILE.
- os.remove(PID_FILE)
- return 0
-
- def install_child_reaper(self):
- #signal.signal(signal.SIGCHLD, self.onSIGCHLD)
- # Ensure that zombie children are automatically reaped.
- xu.autoreap()
-
- def onSIGCHLD(self, signum, frame):
- code = 1
- while code > 0:
- code = os.waitpid(-1, os.WNOHANG)
-
- def start(self,trace=0):
- if self.cleanup(kill=False):
- return 1
-
- # Detach from TTY.
- if not DEBUG:
- os.setsid()
-
- if self.set_user():
- return 1
-
- self.install_child_reaper()
-
- # Fork -- parent writes PID_FILE and exits.
- pid = os.fork()
- if pid:
- # Parent
- pidfile = open(PID_FILE, 'w')
- pidfile.write(str(pid))
- pidfile.close()
- return 0
- # Child
- logfile = self.open_logfile()
- self.redirect_output(logfile)
- if trace:
- self.tracefile = open('/var/log/xend.trace', 'w+', 1)
- self.traceindent = 0
- sys.settrace(self.trace)
- try:
- threading.settrace(self.trace) # Only in Python >= 2.3
- except:
- pass
- self.run()
- return 0
-
- def print_trace(self,str):
- for i in range(self.traceindent):
- self.tracefile.write(" ")
- self.tracefile.write(str)
-
- def trace(self, frame, event, arg):
- if event == 'call':
- code = frame.f_code
- filename = code.co_filename
- m = re.search('.*xenmgr/(.*)', code.co_filename)
- if not m:
- return None
- modulename = m.group(1)
- if re.search('sxp.py', modulename):
- return None
- self.traceindent += 1
- self.print_trace("++++ %s:%s\n"
- % (modulename, code.co_name))
- elif event == 'line':
- filename = frame.f_code.co_filename
- lineno = frame.f_lineno
- self.print_trace("%4d %s" %
- (lineno, linecache.getline(filename, lineno)))
- elif event == 'return':
- code = frame.f_code
- filename = code.co_filename
- m = re.search('.*xenmgr/(.*)', code.co_filename)
- if not m:
- return None
- modulename = m.group(1)
- self.print_trace("---- %s:%s\n"
- % (modulename, code.co_name))
- self.traceindent -= 1
- elif event == 'exception':
- pass
- return self.trace
-
- def open_logfile(self):
- if not os.path.exists(CONTROL_DIR):
- os.makedirs(CONTROL_DIR)
-
- # Open log file. Truncate it if non-empty, and request line buffering.
- if os.path.isfile(LOG_FILE):
- os.rename(LOG_FILE, LOG_FILE+'.old')
- logfile = open(LOG_FILE, 'w+', 1)
- return logfile
-
- def set_user(self):
- # Set the UID.
- try:
- os.setuid(pwd.getpwnam(USER)[2])
- return 0
- except KeyError, error:
- print "Error: no such user '%s'" % USER
- return 1
-
- def redirect_output(self, logfile):
- if DEBUG: return
- # Close down standard file handles
- try:
- os.close(0) # stdin
- os.close(1) # stdout
- os.close(2) # stderr
- except:
- pass
- # Redirect output to log file.
- sys.stdout = sys.stderr = logfile
-
- def stop(self):
- return self.cleanup(kill=True)
-
- def run(self):
- self.createFactories()
- self.listenMgmt()
- self.listenEvent()
- self.listenNotifier()
- self.listenVirq()
- SrvServer.create(bridge=1)
- reactor.run()
-
- def createFactories(self):
- self.channelF = channel.channelFactory()
- self.domainCF = domain.DomainControllerFactory()
- self.blkifCF = blkif.BlkifControllerFactory()
- self.netifCF = netif.NetifControllerFactory()
- self.consoleCF = console.ConsoleControllerFactory()
-
- def listenMgmt(self):
- protocol = MgmtProtocol(self)
- s = os.path.join(CONTROL_DIR, MGMT_SOCK)
- if os.path.exists(s):
- os.unlink(s)
- return reactor.listenUNIXDatagram(s, protocol)
-
- def listenEvent(self):
- protocol = EventFactory(self)
- return reactor.listenTCP(EVENT_PORT, protocol)
-
- def listenNotifier(self):
- protocol = NotifierProtocol(self.channelF)
- p = NotifierPort(self, self.channelF.notifier, protocol, reactor)
- p.startListening()
- return p
-
- def listenVirq(self):
- virqChan = self.channelF.virqChannel(channel.VIRQ_DOM_EXC)
- virqChan.registerClient(VirqClient(self))
-
- def exit(self):
- reactor.diconnectAll()
- sys.exit(0)
-
- def blkif_set_control_domain(self, dom, recreate=0):
- """Set the block device backend control domain.
- """
- return self.blkifCF.setControlDomain(dom, recreate=recreate)
-
- def blkif_get_control_domain(self, dom):
- """Get the block device backend control domain.
- """
- return self.blkifCF.getControlDomain()
-
- def blkif_create(self, dom, recreate=0):
- """Create a block device interface controller.
-
- Returns Deferred
- """
- d = self.blkifCF.createInstance(dom, recreate=recreate)
- return d
-
- def blkifs(self):
- return [ x.sxpr() for x in self.blkifCF.getInstances() ]
-
- def blkif_get(self, dom):
- return self.blkifCF.getInstanceByDom(dom)
-
- def blkif_dev(self, dom, vdev):
- return self.blkifCF.getDomainDevice(dom, vdev)
-
- def blkif_dev_create(self, dom, vdev, mode, segment, recreate=0):
- """Create a block device.
-
- Returns Deferred
- """
- ctrl = self.blkifCF.getInstanceByDom(dom)
- if not ctrl:
- raise ValueError('No blkif controller: %d' % dom)
- print 'blkif_dev_create>', dom, vdev, mode, segment
- d = ctrl.attachDevice(vdev, mode, segment, recreate=recreate)
- return d
-
- def netif_set_control_domain(self, dom, recreate=0):
- """Set the network interface backend control domain.
- """
- return self.netifCF.setControlDomain(dom, recreate=recreate)
-
- def netif_get_control_domain(self, dom):
- """Get the network interface backend control domain.
- """
- return self.netifCF.getControlDomain()
-
- def netif_create(self, dom, recreate=0):
- """Create a network interface controller.
-
- """
- return self.netifCF.createInstance(dom, recreate=recreate)
-
- def netifs(self):
- return [ x.sxpr() for x in self.netifCF.getInstances() ]
-
- def netif_get(self, dom):
- return self.netifCF.getInstanceByDom(dom)
-
- def netif_dev_create(self, dom, vif, vmac, recreate=0):
- """Create a network device.
-
- todo
- """
- ctrl = self.netifCF.getInstanceByDom(dom)
- if not ctrl:
- raise ValueError('No netif controller: %d' % dom)
- d = ctrl.attachDevice(vif, vmac, recreate=recreate)
- return d
-
- def netif_dev(self, dom, vif):
- return self.netifCF.getDomainDevice(dom, vif)
-
- def console_create(self, dom, console_port=None):
- """Create a console for a domain.
- """
- console = self.consoleCF.getInstanceByDom(dom)
- if console is None:
- console = self.consoleCF.createInstance(dom, console_port)
- return console.sxpr()
-
- def consoles(self):
- return [ c.sxpr() for c in self.consoleCF.getInstances() ]
-
- def get_console(self, id):
- return self.consoleCF.getInstance(id)
-
- def get_domain_console(self, dom):
- return self.consoleCF.getInstanceByDom(dom)
-
- def console_disconnect(self, id):
- """Disconnect any connected console client.
- """
- console = self.get_console(id)
- if not console:
- raise ValueError('Invalid console id')
- console.disconnect()
-
- def domain_shutdown(self, dom, reason):
- """Shutdown a domain.
- """
- ctrl = self.domainCF.getInstanceByDom(dom)
- if not ctrl:
- raise ValueError('No domain controller: %d' % dom)
- ctrl.shutdown(reason)
- return 0
-
-def instance():
- global inst
- try:
- inst
- except:
- inst = Daemon()
- return inst
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-from SrvDir import SrvDir
-
-class SrvDeviceDir(SrvDir):
- """Device directory.
- """
-
- pass
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-from twisted.web import error
-from xen.xend import sxp
-from SrvBase import SrvBase
-
-class SrvConstructor:
- """Delayed constructor for sub-servers.
- Does not import the sub-server class or create the object until needed.
- """
-
- def __init__(self, klass):
- """Create a constructor. It is assumed that the class
- should be imported as 'import klass from klass'.
-
- klass name of its class
- """
- self.klass = klass
- self.obj = None
-
- def getobj(self):
- """Get the sub-server object, importing its class and instantiating it if
- necessary.
- """
- if not self.obj:
- exec 'from %s import %s' % (self.klass, self.klass)
- klassobj = eval(self.klass)
- self.obj = klassobj()
- return self.obj
-
-class SrvDir(SrvBase):
- """Base class for directory servlets.
- """
- isLeaf = False
-
- def __init__(self):
- SrvBase.__init__(self)
- self.table = {}
- self.order = []
-
- def getChild(self, x, req):
- if x == '': return self
- val = self.get(x)
- if val is None:
- return error.NoResource('Not found')
- else:
- return val
-
- def get(self, x):
- val = self.table.get(x)
- if val is not None:
- val = val.getobj()
- return val
-
- def add(self, x, xclass = None):
- if xclass is None:
- xclass = 'SrvDir'
- self.table[x] = SrvConstructor(xclass)
- self.order.append(x)
-
- def render_GET(self, req):
- if self.use_sxp(req):
- req.setHeader("Content-type", sxp.mime_type)
- self.ls(req, 1)
- else:
- req.write('<html><head></head><body>')
- self.print_path(req)
- self.ls(req)
- self.form(req)
- req.write('</body></html>')
- return ''
-
- def ls(self, req, use_sxp=0):
- url = req.prePathURL()
- if not url.endswith('/'):
- url += '/'
- if use_sxp:
- req.write('(ls ')
- for k in self.order:
- req.write(' ' + k)
- req.write(')')
- else:
- req.write('<ul>')
- for k in self.order:
- v = self.get(k)
- req.write('<li><a href="%s%s">%s</a></li>'
- % (url, k, k))
- req.write('</ul>')
-
- def form(self, req):
- pass
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-from xen.xend import sxp
-from xen.xend import XendDomain
-from xen.xend import XendConsole
-from xen.xend import PrettyPrint
-from xen.xend.Args import FormFn
-
-from SrvDir import SrvDir
-
-class SrvDomain(SrvDir):
- """Service managing a single domain.
- """
-
- def __init__(self, dom):
- SrvDir.__init__(self)
- self.dom = dom
- self.xd = XendDomain.instance()
- self.xconsole = XendConsole.instance()
-
- def op_unpause(self, op, req):
- val = self.xd.domain_unpause(self.dom.id)
- return val
-
- def op_pause(self, op, req):
- val = self.xd.domain_pause(self.dom.id)
- return val
-
- def op_shutdown(self, op, req):
- val = self.xd.domain_shutdown(self.dom.id)
- req.setResponseCode(202)
- req.setHeader("Location", "%s/.." % req.prePathURL())
- return val
-
- def op_destroy(self, op, req):
- val = self.xd.domain_destroy(self.dom.id)
- req.setHeader("Location", "%s/.." % req.prePathURL())
- return val
-
- def op_save(self, op, req):
- fn = FormFn(self.xd.domain_save,
- [['dom', 'int'],
- ['file', 'str']])
- val = fn(req.args, {'dom': self.dom.id})
- return val
-
- def op_migrate(self, op, req):
- fn = FormFn(self.xd.domain_migrate,
- [['dom', 'int'],
- ['destination', 'str']])
- val = fn(req.args, {'dom': self.dom.id})
- val = 0 # Some migrate id.
- req.setResponseCode(202)
- #req.send_header("Location", "%s/.." % self.path) # Some migrate url.
- return val
-
- def op_pincpu(self, op, req):
- fn = FormFn(self.xd.domain_pincpu,
- [['dom', 'int'],
- ['cpu', 'int']])
- val = fn(req.args, {'dom': self.dom.id})
- return val
-
- def op_cpu_bvt_set(self, op, req):
- fn = FormFn(self.xd.domain_cpu_bvt_set,
- [['dom', 'int'],
- ['mcuadv', 'int'],
- ['warp', 'int'],
- ['warpl', 'int'],
- ['warpu', 'int']])
- val = fn(req.args, {'dom': self.dom.id})
- return val
-
- def op_cpu_atropos_set(self, op, req):
- fn = FormFn(self.xd.domain_cpu_atropos_set,
- [['dom', 'int'],
- ['period', 'int'],
- ['slice', 'int'],
- ['latency', 'int'],
- ['xtratime', 'int']])
- val = fn(req.args, {'dom': self.dom.id})
- return val
-
- def op_vifs(self, op, req):
- return self.xd.domain_vif_ls(self.dom.id)
-
- def op_vif(self, op, req):
- fn = FormFn(self.xd.domain_vif_get,
- [['dom', 'int'],
- ['vif', 'int']])
- val = fn(req.args, {'dom': self.dom.id})
- return val
-
- def op_vif_stats(self, op, req):
- #todo
- fn = FormFn(self.xd.domain_vif_stats,
- [['dom', 'int'],
- ['vif', 'int']])
- #val = fn(req.args, {'dom': self.dom.id})
- val = 999
- #return val
- return val
-
- def op_vif_ip_add(self, op, req):
- fn = FormFn(self.xd.domain_vif_ip_add,
- [['dom', 'int'],
- ['vif', 'int'],
- ['ip', 'str']])
- val = fn(req.args, {'dom': self.dom.id})
- return val
-
- def op_vif_scheduler_set(self, op, req):
- fn = FormFn(self.xd.domain_vif_scheduler_set,
- [['dom', 'int'],
- ['vif', 'int'],
- ['bytes', 'int'],
- ['usecs', 'int']])
- val = fn(req.args, {'dom': self.dom.id})
- return val
-
- def op_vif_scheduler_get(self, op, req):
- fn = FormFn(self.xd.domain_vif_scheduler_set,
- [['dom', 'int'],
- ['vif', 'int']])
- val = fn(req.args, {'dom': self.dom.id})
- return val
-
- def op_vbds(self, op, req):
- return self.xd.domain_vbd_ls(self.dom.id)
-
- def op_vbd(self, op, req):
- fn = FormFn(self.xd.domain_vbd_get,
- [['dom', 'int'],
- ['vbd', 'int']])
- val = fn(req.args, {'dom': self.dom.id})
- return val
-
- def op_vbd_add(self, op, req):
- fn = FormFn(self.xd.domain_vbd_add,
- [['dom', 'int'],
- ['uname', 'str'],
- ['dev', 'str'],
- ['mode', 'str']])
- val = fn(req.args, {'dom': self.dom.id})
- return val
-
- def op_vbd_remove(self, op, req):
- fn = FormFn(self.xd.domain_vbd_remove,
- [['dom', 'int'],
- ['dev', 'str']])
- val = fn(req.args, {'dom': self.dom.id})
- return val
-
- def render_POST(self, req):
- return self.perform(req)
-
- def render_GET(self, req):
- op = req.args.get('op')
- if op and op[0] in ['vifs', 'vif', 'vif_stats', 'vbds', 'vbd']:
- return self.perform(req)
- if self.use_sxp(req):
- req.setHeader("Content-Type", sxp.mime_type)
- sxp.show(self.dom.sxpr(), out=req)
- else:
- req.write('<html><head></head><body>')
- self.print_path(req)
- #self.ls()
- req.write('<p>%s</p>' % self.dom)
- if self.dom.console:
- cinfo = self.dom.console
- cid = cinfo.id
- #todo: Local xref: need to know server prefix.
- req.write('<p><a href="/xend/console/%s">Console %s</a></p>'
- % (cid, cid))
- req.write('<p><a href="%s">Connect to console</a></p>'
- % cinfo.uri())
- if self.dom.config:
- req.write("<code><pre>")
- PrettyPrint.prettyprint(self.dom.config, out=req)
- req.write("</pre></code>")
- req.write('<a href="%s?op=vif_stats&vif=0">vif 0 stats</a>'
- % req.prePathURL())
- self.form(req)
- req.write('</body></html>')
- return ''
-
- def form(self, req):
- req.write('<form method="post" action="%s">' % req.prePathURL())
- req.write('<input type="submit" name="op" value="unpause">')
- req.write('<input type="submit" name="op" value="pause">')
- req.write('<input type="submit" name="op" value="shutdown">')
- req.write('<input type="submit" name="op" value="destroy">')
- req.write('<br><input type="submit" name="op" value="migrate">')
- req.write('To: <input type="text" name="destination">')
- req.write('</form>')
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-from StringIO import StringIO
-
-from twisted.protocols import http
-from twisted.web import error
-
-from xen.xend import sxp
-from xen.xend import XendDomain
-from xen.xend.Args import FormFn
-
-from SrvDir import SrvDir
-from SrvDomain import SrvDomain
-
-class SrvDomainDir(SrvDir):
- """Service that manages the domain directory.
- """
-
- def __init__(self):
- SrvDir.__init__(self)
- self.xd = XendDomain.instance()
-
- def domain(self, x):
- val = None
- try:
- dom = self.xd.domain_get(x)
- val = SrvDomain(dom)
- except KeyError, ex:
- print 'SrvDomainDir>', ex
- pass
- return val
-
- def get(self, x):
- v = SrvDir.get(self, x)
- if v is not None:
- return v
- v = self.domain(x)
- return v
-
- def op_create(self, op, req):
- ok = 0
- try:
- configstring = req.args.get('config')[0]
- print 'config:', configstring
- pin = sxp.Parser()
- pin.input(configstring)
- pin.input_eof()
- config = pin.get_val()
- ok = 1
- except Exception, ex:
- print 'op_create>', ex
- if not ok:
- req.setResponseCode(http.BAD_REQUEST, "Invalid configuration")
- return "Invalid configuration"
- return error.ErrorPage(http.BAD_REQUEST,
- "Invalid",
- "Invalid configuration")
- try:
- deferred = self.xd.domain_create(config)
- deferred.addCallback(self._cb_op_create, configstring, req)
- return deferred
- except Exception, ex:
- raise
- #return ['err', str(ex) ]
- #req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
- #return str(ex)
- #return error.ErrorPage(http.BAD_REQUEST,
- # "Error creating domain",
- # str(ex))
-
-
- def _cb_op_create(self, dominfo, configstring, req):
- """Callback to handle deferred domain creation.
- """
- dom = dominfo.id
- domurl = "%s/%s" % (req.prePathURL(), dom)
- req.setResponseCode(201, "created")
- req.setHeader("Location", domurl)
- if self.use_sxp(req):
- return dominfo.sxpr()
- else:
- out = StringIO()
- print >> out, ('<p> Created <a href="%s">Domain %s</a></p>'
- % (domurl, dom))
- print >> out, '<p><pre>'
- print >> out, configstring
- print >> out, '</pre></p>'
- val = out.getvalue()
- out.close()
- return val
-
- def op_restore(self, op, req):
- fn = FormFn(self.xd.domain_restore,
- [['file', 'str']])
- val = fn(req.args)
- return val
-
- def render_POST(self, req):
- return self.perform(req)
-
- def render_GET(self, req):
- if self.use_sxp(req):
- req.setHeader("Content-Type", sxp.mime_type)
- self.ls_domain(req, 1)
- else:
- req.write("<html><head></head><body>")
- self.print_path(req)
- self.ls(req)
- self.ls_domain(req)
- self.form(req)
- req.write("</body></html>")
- return ''
-
- def ls_domain(self, req, use_sxp=0):
- url = req.prePathURL()
- if not url.endswith('/'):
- url += '/'
- if use_sxp:
- domains = self.xd.domain_ls()
- sxp.show(domains, out=req)
- else:
- domains = self.xd.domains()
- domains.sort(lambda x, y: cmp(x.id, y.id))
- req.write('<ul>')
- for d in domains:
- req.write('<li><a href="%s%s"> Domain %s</a>'
- % (url, d.id, d.id))
- req.write('name=%s' % d.name)
- req.write('memory=%d'% d.memory)
- req.write('</li>')
- req.write('</ul>')
-
- def form(self, req):
- req.write('<form method="post" action="%s" enctype="multipart/form-data">'
- % req.prePathURL())
- req.write('<button type="submit" name="op" value="create">Create Domain</button>')
- req.write('Config <input type="file" name="config"><br>')
- req.write('</form>')
- req.write('<form method="post" action="%s" enctype="multipart/form-data">'
- % req.prePathURL())
- req.write('<button type="submit" name="op" value="create">Restore Domain</button>')
- req.write('State <input type="string" name="state"><br>')
- req.write('</form>')
-
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-from xen.xend import sxp
-from xen.xend import EventServer
-from SrvDir import SrvDir
-
-class SrvEventDir(SrvDir):
- """Event directory.
- """
-
- def __init__(self):
- SrvDir.__init__(self)
- self.eserver = EventServer.instance()
-
- def op_inject(self, op, req):
- eventstring = req.args.get('event')
- pin = sxp.Parser()
- pin.input(eventstring)
- pin.input_eof()
- sxpr = pin.get_val()
- self.eserver.inject(sxp.name(sxpr), sxpr)
- if req.use_sxp:
- sxp.name(sxpr)
- else:
- return '<code>' + eventstring + '</code>'
-
- def render_POST(self, req):
- return self.perform(req)
-
- def form(self, req):
- action = req.prePathURL()
- req.write('<form method="post" action="%s" enctype="multipart/form-data">'
- % action)
- req.write('<button type="submit" name="op" value="inject">Inject</button>')
- req.write('Event <input type="text" name="event" size="40"><br>')
- req.write('</form>')
- req.write('<form method="post" action="%s" enctype="multipart/form-data">'
- % action)
- req.write('<button type="submit" name="op" value="inject">Inject</button>')
- req.write('Event file<input type="file" name="event"><br>')
- req.write('</form>')
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-import os
-from SrvDir import SrvDir
-from xen.xend import sxp
-from xen.xend import XendNode
-
-class SrvNode(SrvDir):
- """Information about the node.
- """
-
- def __init__(self):
- SrvDir.__init__(self)
- self.xn = XendNode.instance()
-
- def op_shutdown(self, op, req):
- val = self.xn.shutdown()
- return val
-
- def op_reboot(self, op, req):
- val = self.xn.reboot()
- return val
-
- def op_cpu_rrobin_slice_set(self, op, req):
- fn = FormFn(self.xn.cpu_rrobin_slice_set,
- [['slice', 'int']])
- val = fn(req.args, {})
- return val
-
- def op_cpu_bvt_slice_set(self, op, req):
- fn = FormFn(self.xn.cpu_bvt_slice_set,
- [['slice', 'int']])
- val = fn(req.args, {})
- return val
-
- def render_POST(self, req):
- return self.perform(req)
-
- def render_GET(self, req):
- if self.use_sxp(req):
- req.setHeader("Content-Type", sxp.mime_type)
- sxp.show(['node'] + self.info(), out=req)
- else:
- req.write('<html><head></head><body>')
- self.print_path(req)
- req.write('<ul>')
- for d in self.info():
- req.write('<li> %10s: %s' % (d[0], str(d[1])))
- req.write('</ul>')
- req.write('</body></html>')
- return ''
-
- def info(self):
- return self.xn.info()
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-from xen.xend import XendRoot
-xroot = XendRoot.instance()
-from SrvDir import SrvDir
-
-class SrvRoot(SrvDir):
- """The root of the xend server.
- """
-
- """Server sub-components. Each entry is (name, class), where
- 'name' is the entry name and 'class' is the name of its class.
- """
- #todo Get this list from the XendRoot config.
- subdirs = [
- ('node', 'SrvNode' ),
- ('domain', 'SrvDomainDir' ),
- ('console', 'SrvConsoleDir' ),
- ('event', 'SrvEventDir' ),
- ('device', 'SrvDeviceDir' ),
- ('vnet', 'SrvVnetDir' ),
- ]
-
- def __init__(self):
- SrvDir.__init__(self)
- for (name, klass) in self.subdirs:
- self.add(name, klass)
- for (name, klass) in self.subdirs:
- self.get(name)
- xroot.start()
+++ /dev/null
-#!/usr/bin/python2
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-"""Example xend HTTP and console server.
-
- Can be accessed from a browser or from a program.
- Do 'python SrvServer.py' to run the server.
- Then point a web browser at http://localhost:8000/xend and follow the links.
- Most are stubs, except /domain which has a list of domains and a 'create domain'
- button.
-
- You can also access the server from a program.
- Do 'python XendClient.py' to run a few test operations.
-
- The data served differs depending on the client (as defined by User-Agent
- and Accept in the HTTP headers). If the client is a browser, data
- is returned in HTML, with interactive forms. If the client is a program,
- data is returned in SXP format, with no forms.
-
- The server serves to the world by default. To restrict it to the local host
- change 'interface' in main().
-
- Mike Wray <mike.wray@hp.com>
-"""
-# todo Support security settings etc. in the config file.
-# todo Support command-line args.
-
-from twisted.web import server
-from twisted.web import resource
-from twisted.internet import reactor
-
-from xen.xend import XendRoot
-xroot = XendRoot.instance()
-
-from xen.xend import Vifctl
-
-from SrvRoot import SrvRoot
-
-def create(port=None, interface=None, bridge=0):
- if port is None: port = 8000
- if interface is None: interface = ''
- if bridge or xroot.rebooted:
- init_bridge()
- root = resource.Resource()
- xend = SrvRoot()
- root.putChild('xend', xend)
- site = server.Site(root)
- reactor.listenTCP(port, site, interface=interface)
-
-def init_bridge():
- Vifctl.init()
-
-def main(port=None, interface=None):
- create(port, interface)
- reactor.run()
-
-
-if __name__ == '__main__':
- main()
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-from SrvDir import SrvDir
-
-class SrvVnetDir(SrvDir):
- """Vnet directory.
- """
-
- pass
+++ /dev/null
-from twisted.internet import defer
-
-from xen.xend import sxp
-from xen.xend import PrettyPrint
-
-import channel
-import controller
-from messages import *
-
-class BlkifControllerFactory(controller.ControllerFactory):
- """Factory for creating block device interface controllers.
- Also handles the 'back-end' channel to the device driver domain.
- """
-
- def __init__(self):
- controller.ControllerFactory.__init__(self)
-
- self.majorTypes = [ CMSG_BLKIF_BE ]
-
- self.subTypes = {
- CMSG_BLKIF_BE_CREATE : self.recv_be_create,
- CMSG_BLKIF_BE_CONNECT : self.recv_be_connect,
- CMSG_BLKIF_BE_VBD_CREATE : self.recv_be_vbd_create,
- CMSG_BLKIF_BE_VBD_GROW : self.recv_be_vbd_grow,
- CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
- }
- self.attached = 1
- self.registerChannel()
-
- def createInstance(self, dom, recreate=0):
- d = self.addDeferred()
- blkif = self.getInstanceByDom(dom)
- if blkif:
- self.callDeferred(blkif)
- else:
- blkif = BlkifController(self, dom)
- self.addInstance(blkif)
- if recreate:
- self.callDeferred(blkif)
- else:
- blkif.send_be_create()
- return d
-
- def getDomainDevices(self, dom):
- blkif = self.getInstanceByDom(dom)
- return (blkif and blkif.getDevices()) or []
-
- def getDomainDevice(self, dom, vdev):
- blkif = self.getInstanceByDom(dom)
- return (blkif and blkif.getDevice(vdev)) or None
-
- def setControlDomain(self, dom, recreate=0):
- if self.dom == dom: return
- self.deregisterChannel()
- if not recreate:
- self.attached = 0
- self.dom = dom
- self.registerChannel()
- #
- #if xend.blkif.be_port:
- # xend.blkif.recovery = True
- #xend.blkif.be_port = xend.main.port_from_dom(dom)
-
- def getControlDomain(self):
- return self.dom
-
- def reattachDevice(self, dom, vdev):
- blkif = self.getInstanceByDom(dom)
- if blkif:
- blkif.reattachDevice(vdev)
- self.attached = self.devicesAttached()
- if self.attached:
- self.reattached()
-
- def devicesAttached(self):
- """Check if all devices are attached.
- """
- attached = 1
- for blkif in self.getInstances():
- if not blkif.attached:
- attached = 0
- break
- return attached
-
- def reattached(self):
- for blkif in self.getInstances():
- blkif.reattached()
-
- def recv_be_create(self, msg, req):
- #print 'recv_be_create>'
- val = unpackMsg('blkif_be_create_t', msg)
- blkif = self.getInstanceByDom(val['domid'])
- self.callDeferred(blkif)
-
- def recv_be_connect(self, msg, req):
- #print 'recv_be_create>'
- val = unpackMsg('blkif_be_connect_t', msg)
- blkif = self.getInstanceByDom(val['domid'])
- if blkif:
- blkif.send_fe_interface_status_changed()
- else:
- pass
-
- def recv_be_vbd_create(self, msg, req):
- #print 'recv_be_vbd_create>'
- val = unpackMsg('blkif_be_vbd_create_t', msg)
- blkif = self.getInstanceByDom(val['domid'])
- if blkif:
- blkif.send_be_vbd_grow(val['vdevice'])
- else:
- pass
-
- def recv_be_vbd_grow(self, msg, req):
- #print 'recv_be_vbd_grow>'
- val = unpackMsg('blkif_be_vbd_grow_t', msg)
- # Check status?
- if self.attached:
- self.callDeferred(0)
- else:
- self.reattachDevice(val['domid'], val['vdevice'])
-
- def recv_be_driver_status_changed(self, msg, req):
- val = unpackMsg('blkif_be_driver_status_changed_t', msg)
- status = val['status']
- if status == BLKIF_DRIVER_STATUS_UP and not self.attached:
- for blkif in self.getInstances():
- blkif.detach()
-
-class BlkDev(controller.Dev):
- """Info record for a block device.
- """
-
- def __init__(self, ctrl, vdev, mode, segment):
- controller.Dev.__init__(self, ctrl)
- self.vdev = vdev
- self.mode = mode
- self.device = segment['device']
- self.start_sector = segment['start_sector']
- self.nr_sectors = segment['nr_sectors']
- self.attached = 1
-
- def readonly(self):
- return 'w' not in self.mode
-
- def sxpr(self):
- val = ['blkdev', ['vdev', self.vdev], ['mode', self.mode] ]
- return val
-
- def destroy(self):
- print 'BlkDev>destroy>', self.vdev
- PrettyPrint.prettyprint(self.sxpr())
- self.controller.send_be_vbd_destroy(self.vdev)
-
-class BlkifController(controller.Controller):
- """Block device interface controller. Handles all block devices
- for a domain.
- """
-
- def __init__(self, factory, dom):
- #print 'BlkifController> dom=', dom
- controller.Controller.__init__(self, factory, dom)
- self.devices = {}
-
- self.majorTypes = [ CMSG_BLKIF_FE ]
-
- self.subTypes = {
- CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED:
- self.recv_fe_driver_status_changed,
- CMSG_BLKIF_FE_INTERFACE_CONNECT :
- self.recv_fe_interface_connect,
- }
- self.attached = 1
- self.evtchn = None
- self.registerChannel()
- #print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx
-
- def sxpr(self):
- val = ['blkif', ['dom', self.dom]]
- if self.evtchn:
- val.append(['evtchn',
- self.evtchn['port1'],
- self.evtchn['port2']])
- return val
-
- def lostChannel(self):
- print 'BlkifController>lostChannel>', 'dom=', self.dom
- #self.destroyDevices()
- controller.Controller.lostChannel(self)
-
- def getDevices(self):
- return self.devices.values()
-
- def getDevice(self, vdev):
- return self.devices.get(vdev)
-
- def addDevice(self, vdev, mode, segment):
- if vdev in self.devices: return None
- dev = BlkDev(self, vdev, mode, segment)
- self.devices[vdev] = dev
- return dev
-
- def attachDevice(self, vdev, mode, segment, recreate=0):
- """Attach a device to the specified interface.
- """
- #print 'BlkifController>attach_device>', self.dom, vdev, mode, segment
- dev = self.addDevice(vdev, mode, segment)
- if not dev: return -1
- if recreate:
- d = defer.Deferred()
- d.callback(self)
- else:
- self.send_be_vbd_create(vdev)
- d = self.factory.addDeferred()
- return d
-
- def destroy(self):
- print 'BlkifController>destroy> dom=', self.dom
- def cb_destroy(val):
- self.send_be_destroy()
- d = self.factory.addDeferred()
- d.addCallback(cb_destroy)
- self.send_be_disconnect()
- #self.destroyDevices()
-
- def destroyDevices(self):
- for dev in self.getDevices():
- dev.destroy()
-
- def detach(self):
- """Detach all devices, when the back-end control domain has changed.
- """
- self.attached = 0
- for dev in self.devices.values():
- dev.attached = 0
- self.send_be_vbd_create(vdev)
-
- def reattachDevice(self, vdev):
- """Reattach a device, when the back-end control domain has changed.
- """
- dev = self.devices[vdev]
- dev.attached = 1
- attached = 1
- for dev in self.devices.values():
- if not dev.attached:
- attached = 0
- break
- self.attached = attached
- return self.attached
-
- def reattached(self):
- """All devices have been reattached after the back-end control
- domain has changed.
- """
- msg = packMsg('blkif_fe_interface_status_changed_t',
- { 'handle' : 0,
- 'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED})
- self.writeRequest(msg)
-
- def recv_fe_driver_status_changed(self, msg, req):
- msg = packMsg('blkif_fe_interface_status_changed_t',
- { 'handle' : 0,
- 'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED,
- 'evtchn' : 0 })
- self.writeRequest(msg)
-
- def recv_fe_interface_connect(self, msg, req):
- val = unpackMsg('blkif_fe_interface_connect_t', msg)
- self.evtchn = channel.eventChannel(0, self.dom)
- print 'recv_fe_interface_connect>'
- PrettyPrint.prettyprint(self.sxpr())
- msg = packMsg('blkif_be_connect_t',
- { 'domid' : self.dom,
- 'blkif_handle' : val['handle'],
- 'evtchn' : self.evtchn['port1'],
- 'shmem_frame' : val['shmem_frame'] })
- self.factory.writeRequest(msg)
- pass
-
- #def recv_fe_interface_status_changed(self, msg, req):
- # (hnd, status, chan) = unpackMsg('blkif_fe_interface_status_changed_t', msg)
- # print 'recv_fe_interface_status_changed>', hnd, status, chan
- # pass
-
- def send_fe_interface_status_changed(self):
- msg = packMsg('blkif_fe_interface_status_changed_t',
- { 'handle' : 0,
- 'status' : BLKIF_INTERFACE_STATUS_CONNECTED,
- 'evtchn' : self.evtchn['port2'] })
- self.writeRequest(msg)
-
- def send_be_create(self):
- msg = packMsg('blkif_be_create_t',
- { 'domid' : self.dom,
- 'blkif_handle' : 0 })
- self.factory.writeRequest(msg)
-
- def send_be_disconnect(self):
- print '>BlkifController>send_be_disconnect>', 'dom=', self.dom
- msg = packMsg('blkif_be_disconnect_t',
- { 'domid' : self.dom,
- 'blkif_handle' : 0 })
- self.factory.writeRequest(msg)
-
- def send_be_destroy(self):
- print '>BlkifController>send_be_destroy>', 'dom=', self.dom
- msg = packMsg('blkif_be_destroy_t',
- { 'domid' : self.dom,
- 'blkif_handle' : 0 })
- self.factory.writeRequest(msg)
-
- def send_be_vbd_create(self, vdev):
- dev = self.devices[vdev]
- msg = packMsg('blkif_be_vbd_create_t',
- { 'domid' : self.dom,
- 'blkif_handle' : 0,
- 'vdevice' : dev.vdev,
- 'readonly' : dev.readonly() })
- self.factory.writeRequest(msg)
-
- def send_be_vbd_grow(self, vdev):
- dev = self.devices[vdev]
- msg = packMsg('blkif_be_vbd_grow_t',
- { 'domid' : self.dom,
- 'blkif_handle' : 0,
- 'vdevice' : dev.vdev,
- 'extent.device' : dev.device,
- 'extent.sector_start' : dev.start_sector,
- 'extent.sector_length' : dev.nr_sectors })
- self.factory.writeRequest(msg)
-
- def send_be_vbd_destroy(self, vdev):
- print '>BlkifController>send_be_vbd_destroy>', 'dom=', self.dom, 'vdev=', vdev
- PrettyPrint.prettyprint(self.sxpr())
- dev = self.devices[vdev]
- msg = packMsg('blkif_be_vbd_destroy_t',
- { 'domid' : self.dom,
- 'blkif_handle' : 0,
- 'vdevice' : dev.vdev })
- del self.devices[vdev]
- self.factory.writeRequest(msg)
-
+++ /dev/null
-import xen.ext.xc; xc = xen.ext.xc.new()
-from xen.ext import xu
-from messages import msgTypeName
-
-VIRQ_MISDIRECT = 0 # Catch-all interrupt for unbound VIRQs.
-VIRQ_TIMER = 1 # Timebase update, and/or requested timeout.
-VIRQ_DEBUG = 2 # Request guest to dump debug info.
-VIRQ_CONSOLE = 3 # (DOM0) bytes received on emergency console.
-VIRQ_DOM_EXC = 4 # (DOM0) Exceptional event for some domain.
-
-def eventChannel(dom1, dom2):
- return xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2)
-
-class ChannelFactory:
- """Factory for creating channels.
- Maintains a table of channels.
- """
-
- """ Channels indexed by index. """
- channels = {}
-
- def __init__(self):
- """Constructor - do not use. Use the channelFactory function."""
- self.notifier = xu.notifier()
-
- def addChannel(self, channel):
- """Add a channel.
- """
- idx = channel.idx
- self.channels[idx] = channel
- self.notifier.bind(idx)
- # Try to wake it up
- #self.notifier.unmask(idx)
- #channel.notify()
-
- def getChannel(self, idx):
- """Get the channel with the given index (if any).
- """
- return self.channels.get(idx)
-
- def delChannel(self, idx):
- """Remove the channel with the given index (if any).
- """
- if idx in self.channels:
- del self.channels[idx]
- self.notifier.unbind(idx)
-
- def domChannel(self, dom):
- """Get the channel for the given domain.
- Construct if necessary.
- """
- dom = int(dom)
- for chan in self.channels.values():
- if not isinstance(chan, Channel): continue
- if chan.dom == dom:
- return chan
- chan = Channel(self, dom)
- self.addChannel(chan)
- return chan
-
- def virqChannel(self, virq):
- """Get the channel for the given virq.
- Construct if necessary.
- """
- for chan in self.channels.values():
- if not isinstance(chan, VirqChannel): continue
- if chan.virq == virq:
- return chan
- chan = VirqChannel(self, virq)
- self.addChannel(chan)
- return chan
-
- def channelClosed(self, channel):
- """The given channel has been closed - remove it.
- """
- self.delChannel(channel.idx)
-
- def createPort(self, dom):
- """Create a port for a channel to the given domain.
- """
- return xu.port(dom)
-
-def channelFactory():
- """Singleton constructor for the channel factory.
- Use this instead of the class constructor.
- """
- global inst
- try:
- inst
- except:
- inst = ChannelFactory()
- return inst
-
-class BaseChannel:
- """Abstract superclass for channels.
-
- The subclass constructor must set idx to the port to use.
- """
-
- def __init__(self, factory):
- self.factory = factory
- self.idx = -1
- self.closed = 0
-
- def getIndex(self):
- """Get the channel index.
- """
- return self.idx
-
- def notificationReceived(self, type):
- """Called when a notification is received.
- Closes the channel on error, otherwise calls
- handleNotification(type), which should be defined
- in a subclass.
- """
- #print 'notificationReceived> type=', type, self
- if self.closed: return
- if type == self.factory.notifier.EXCEPTION:
- print 'notificationReceived> EXCEPTION'
- info = xc.evtchn_status(self.idx)
- if info['status'] == 'unbound':
- print 'notificationReceived> EXCEPTION closing...'
- self.close()
- return
- self.handleNotification(type)
-
- def close(self):
- """Close the channel. Calls channelClosed() on the factory.
- Override in subclass.
- """
- self.factory.channelClosed(self)
-
- def handleNotification(self, type):
- """Handle notification.
- Define in subclass.
- """
- pass
-
-
-class VirqChannel(BaseChannel):
- """A channel for handling a virq.
- """
-
- def __init__(self, factory, virq):
- """Create a channel for the given virq using the given factory.
-
- Do not call directly, use virqChannel on the factory.
- """
- BaseChannel.__init__(self, factory)
- self.virq = virq
- # Notification port (int).
- self.port = xc.evtchn_bind_virq(virq)
- self.idx = self.port
- # Clients to call when a virq arrives.
- self.clients = []
-
- def __repr__(self):
- return ('<VirqChannel virq=%d port=%d>'
- % (self.virq, self.port))
-
- def getVirq(self):
- """Get the channel's virq.
- """
- return self.virq
-
- def close(self):
- """Close the channel. Calls lostChannel(self) on all its clients and
- channelClosed() on the factory.
- """
- for c in self.clients:
- c.lostChannel(self)
- del self.clients
- BaseChannel.close(self)
-
- def registerClient(self, client):
- """Register a client. The client will be called with
- client.virqReceived(virq) when a virq is received.
- The client will be called with client.lostChannel(self) if the
- channel is closed.
- """
- self.clients.append(client)
-
- def handleNotification(self, type):
- for c in self.clients:
- c.virqReceived(self.virq)
-
- def notify(self):
- xc.evtchn_send(self.port)
-
-
-class Channel(BaseChannel):
- """A control channel to a domain. Messages for the domain device controllers
- are multiplexed over the channel (console, block devs, net devs).
- """
-
- def __init__(self, factory, dom):
- """Create a channel to the given domain using the given factory.
-
- Do not call directly, use domChannel on the factory.
- """
- BaseChannel.__init__(self, factory)
- # Domain.
- self.dom = int(dom)
- # Domain port (object).
- self.port = self.factory.createPort(dom)
- # Channel port (int).
- self.idx = self.port.local_port
- # Registered devices.
- self.devs = []
- # Devices indexed by the message types they handle.
- self.devs_by_type = {}
- # Output queue.
- self.queue = []
- self.closed = 0
-
- def getLocalPort(self):
- """Get the local port.
- """
- return self.port.local_port
-
- def getRemotePort(self):
- """Get the remote port.
- """
- return self.port.remote_port
-
- def close(self):
- """Close the channel. Calls lostChannel() on all its devices and
- channelClosed() on the factory.
- """
- self.closed = 1
- for d in self.devs:
- d.lostChannel()
- self.factory.channelClosed(self)
- self.devs = []
- self.devs_by_type = {}
-
- def registerDevice(self, types, dev):
- """Register a device controller.
-
- @param types message types the controller handles
- @param dev device controller
- """
- if self.closed: return
- self.devs.append(dev)
- for ty in types:
- self.devs_by_type[ty] = dev
-
- def deregisterDevice(self, dev):
- """Remove the registration for a device controller.
-
- @param dev device controller
- """
- if dev in self.devs:
- self.devs.remove(dev)
- types = [ ty for (ty, d) in self.devs_by_type.items() if d == dev ]
- for ty in types:
- del self.devs_by_type[ty]
-
- def getDevice(self, type):
- """Get the device controller handling a message type.
-
- @param type message type
- @returns controller or None
- """
- return self.devs_by_type.get(type)
-
- def getMessageType(self, msg):
- """Get a 2-tuple of the message type and subtype.
- """
- hdr = msg.get_header()
- return (hdr['type'], hdr.get('subtype'))
-
- def __repr__(self):
- return ('<Channel dom=%d ports=%d:%d>'
- % (self.dom,
- self.port.local_port,
- self.port.remote_port))
-
- def handleNotification(self, type):
- work = 0
- work += self.handleRequests()
- work += self.handleResponses()
- work += self.handleWrites()
- if work:
- self.notify()
-
- def notify(self):
- self.port.notify()
-
- def handleRequests(self):
- work = 0
- while 1:
- msg = self.readRequest()
- if not msg: break
- self.requestReceived(msg)
- work += 1
- return work
-
- def requestReceived(self, msg):
- (ty, subty) = self.getMessageType(msg)
- #todo: Must respond before writing any more messages.
- #todo: Should automate this (respond on write)
- self.port.write_response(msg)
- dev = self.getDevice(ty)
- if dev:
- dev.requestReceived(msg, ty, subty)
- else:
- print ("requestReceived> No device: Message type %s %d:%d"
- % (msgTypeName(ty, subty), ty, subty)), self
-
- def handleResponses(self):
- work = 0
- while 1:
- msg = self.readResponse()
- if not msg: break
- self.responseReceived(msg)
- work += 1
- return work
-
- def responseReceived(self, msg):
- (ty, subty) = self.getMessageType(msg)
- dev = self.getDevice(ty)
- if dev:
- dev.responseReceived(msg, ty, subty)
- else:
- print ("responseReceived> No device: Message type %d:%d"
- % (msgTypeName(ty, subty), ty, subty)), self
-
- def handleWrites(self):
- work = 0
- # Pull data from producers.
- for dev in self.devs:
- work += dev.produceRequests()
- # Flush the queue.
- while self.queue and self.port.space_to_write_request():
- msg = self.queue.pop(0)
- self.port.write_request(msg)
- work += 1
- return work
-
- def writeRequest(self, msg, notify=1):
- if self.closed:
- val = -1
- elif self.writeReady():
- self.port.write_request(msg)
- if notify: self.notify()
- val = 1
- else:
- self.queue.append(msg)
- val = 0
- return val
-
- def writeResponse(self, msg):
- if self.closed: return -1
- self.port.write_response(msg)
- return 1
-
- def writeReady(self):
- if self.closed or self.queue: return 0
- return self.port.space_to_write_request()
-
- def readRequest(self):
- if self.closed:
- return None
- if self.port.request_to_read():
- val = self.port.read_request()
- else:
- val = None
- return val
-
- def readResponse(self):
- if self.closed:
- return None
- if self.port.response_to_read():
- val = self.port.read_response()
- else:
- val = None
- return val
+++ /dev/null
-
-from twisted.internet import reactor
-from twisted.internet import protocol
-from twisted.protocols import telnet
-
-from xen.ext import xu
-
-from xen.xend import EventServer
-eserver = EventServer.instance()
-
-import controller
-from messages import *
-from params import *
-
-"""Telnet binary option."""
-TRANSMIT_BINARY = '0'
-WILL = chr(251)
-IAC = chr(255)
-
-class ConsoleProtocol(protocol.Protocol):
- """Asynchronous handler for a console TCP socket.
- """
-
- def __init__(self, controller, idx):
- self.controller = controller
- self.idx = idx
- self.addr = None
- self.binary = 0
-
- def connectionMade(self):
- peer = self.transport.getPeer()
- self.addr = (peer.host, peer.port)
- if self.controller.connect(self.addr, self):
- self.transport.write("Cannot connect to console %d on domain %d\n"
- % (self.idx, self.controller.dom))
- self.loseConnection()
- return
- else:
- # KAF: A nice quiet successful connect. Don't bother with telnet
- # control sequence -- telnet is not the appropriate protocol here.
- #self.transport.write("Connected to console %d on domain %d\n"
- # % (self.idx, self.controller.dom))
- #self.setTelnetTransmitBinary()
- eserver.inject('xend.console.connect',
- [self.idx, self.addr[0], self.addr[1]])
-
- def setTelnetTransmitBinary(self):
- """Send the sequence to set the telnet TRANSMIT-BINARY option.
- """
- self.write(IAC + WILL + TRANSMIT_BINARY)
-
- def dataReceived(self, data):
- if self.controller.handleInput(self, data):
- self.loseConnection()
-
- def write(self, data):
- #if not self.connected: return -1
- self.transport.write(data)
- return len(data)
-
- def connectionLost(self, reason=None):
- eserver.inject('xend.console.disconnect',
- [self.idx, self.addr[0], self.addr[1]])
- self.controller.disconnect()
-
- def loseConnection(self):
- self.transport.loseConnection()
-
-class ConsoleFactory(protocol.ServerFactory):
- """Asynchronous handler for a console server socket.
- """
- protocol = ConsoleProtocol
-
- def __init__(self, controller, idx):
- #protocol.ServerFactory.__init__(self)
- self.controller = controller
- self.idx = idx
-
- def buildProtocol(self, addr):
- proto = self.protocol(self.controller, self.idx)
- proto.factory = self
- return proto
-
-class ConsoleControllerFactory(controller.ControllerFactory):
- """Factory for creating console controllers.
- """
-
- def createInstance(self, dom, console_port=None):
- if console_port is None:
- console_port = CONSOLE_PORT_BASE + dom
- console = ConsoleController(self, dom, console_port)
- self.addInstance(console)
- eserver.inject('xend.console.create',
- [console.idx, console.dom, console.console_port])
- return console
-
- def consoleClosed(self, console):
- eserver.inject('xend.console.close', console.idx)
- self.delInstance(console)
-
-class ConsoleController(controller.Controller):
- """Console controller for a domain.
- Does not poll for i/o itself, but relies on the notifier to post console
- output and the connected TCP sockets to post console input.
- """
-
- def __init__(self, factory, dom, console_port):
- #print 'ConsoleController> dom=', dom, type(dom)
- controller.Controller.__init__(self, factory, dom)
- self.majorTypes = [ CMSG_CONSOLE ]
- self.status = "new"
- self.addr = None
- self.conn = None
- self.rbuf = xu.buffer()
- self.wbuf = xu.buffer()
- self.console_port = console_port
-
- self.registerChannel()
- self.listener = None
- self.listen()
- #print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx
-
- def sxpr(self):
- val =['console',
- ['status', self.status ],
- ['id', self.idx ],
- ['domain', self.dom ],
- ['local_port', self.channel.getLocalPort() ],
- ['remote_port', self.channel.getRemotePort() ],
- ['console_port', self.console_port ] ]
- if self.addr:
- val.append(['connected', self.addr[0], self.addr[1]])
- return val
-
- def ready(self):
- return not (self.closed() or self.rbuf.empty())
-
- def closed(self):
- return self.status == 'closed'
-
- def connected(self):
- return self.status == 'connected'
-
- def close(self):
- try:
- #print 'ConsoleController> close dom=', self.dom
- self.status = "closed"
- if self.conn:
- self.conn.loseConnection()
- self.listener.stopListening()
- self.deregisterChannel()
- self.lostChannel()
- except Exception, ex:
- print 'ConsoleController>close>', ex
- raise
-
- def listen(self):
- """Listen for TCP connections to the console port..
- """
- if self.closed(): return
- self.status = "listening"
- if self.listener:
- #self.listener.startListening()
- pass
- else:
- f = ConsoleFactory(self, self.idx)
- self.listener = reactor.listenTCP(self.console_port, f)
-
- def connect(self, addr, conn):
- if self.closed(): return -1
- if self.connected(): return -1
- self.addr = addr
- self.conn = conn
- self.status = "connected"
- self.handleOutput()
- return 0
-
- def disconnect(self):
- if self.conn:
- self.conn.loseConnection()
- self.addr = None
- self.conn = None
- self.listen()
-
- def requestReceived(self, msg, type, subtype):
- #print '***Console', self.dom, msg.get_payload()
- self.rbuf.write(msg.get_payload())
- self.handleOutput()
-
- def responseReceived(self, msg, type, subtype):
- pass
-
- def produceRequests(self):
- # Send as much pending console data as there is room for.
- work = 0
- while not self.wbuf.empty() and self.channel.writeReady():
- msg = xu.message(CMSG_CONSOLE, 0, 0)
- msg.append_payload(self.wbuf.read(msg.MAX_PAYLOAD))
- work += self.channel.writeRequest(msg, notify=0)
- return work
-
- def handleInput(self, conn, data):
- """Handle some external input aimed at the console.
- Called from a TCP connection (conn).
- """
- if self.closed(): return -1
- if conn != self.conn: return 0
- self.wbuf.write(data)
- if self.produceRequests():
- self.channel.notify()
- return 0
-
- def handleOutput(self):
- """Handle buffered output from the console.
- Sends it to the connected console (if any).
- """
- if self.closed():
- #print 'Console>handleOutput> closed'
- return -1
- if not self.conn:
- #print 'Console>handleOutput> not connected'
- return 0
- while not self.rbuf.empty():
- try:
- #print 'Console>handleOutput> writing...'
- bytes = self.conn.write(self.rbuf.peek())
- if bytes > 0:
- self.rbuf.discard(bytes)
- except socket.error, error:
- pass
- #print 'Console>handleOutput<'
- return 0
+++ /dev/null
-from twisted.internet import defer
-
-import channel
-from messages import msgTypeName
-
-class CtrlMsgRcvr:
- """Abstract class for things that deal with a control interface to a domain.
- """
-
-
- def __init__(self):
- self.channelFactory = channel.channelFactory()
- self.majorTypes = [ ]
- self.subTypes = {}
- self.dom = None
- self.channel = None
- self.idx = None
-
- def requestReceived(self, msg, type, subtype):
- method = self.subTypes.get(subtype)
- if method:
- method(msg, 1)
- else:
- print ('requestReceived> No handler: Message type %s %d:%d'
- % (msgTypeName(type, subtype), type, subtype)), self
-
- def responseReceived(self, msg, type, subtype):
- method = self.subTypes.get(subtype)
- if method:
- method(msg, 0)
- else:
- print ('responseReceived> No handler: Message type %s %d:%d'
- % (msgTypeName(type, subtype), type, subtype)), self
-
- def lostChannel(self):
- pass
-
- def registerChannel(self):
- #print 'CtrlMsgRcvr>registerChannel>', self
- self.channel = self.channelFactory.domChannel(self.dom)
- self.idx = self.channel.getIndex()
- if self.majorTypes:
- self.channel.registerDevice(self.majorTypes, self)
-
- def deregisterChannel(self):
- #print 'CtrlMsgRcvr>deregisterChannel>', self
- if self.channel:
- self.channel.deregisterDevice(self)
- del self.channel
-
- def produceRequests(self):
- return 0
-
- def writeRequest(self, msg):
- if self.channel:
- self.channel.writeRequest(msg)
- else:
- print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self
-
- def writeResponse(self, msg):
- if self.channel:
- self.channel.writeResponse(msg)
- else:
- print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self
-
-class ControllerFactory(CtrlMsgRcvr):
- """Abstract class for factories creating controllers.
- Maintains a table of instances.
- """
-
- def __init__(self):
- CtrlMsgRcvr.__init__(self)
- self.instances = {}
- self.dlist = []
- self.dom = 0
- # Timeout (in seconds) for deferreds.
- self.timeout = 10
-
- def addInstance(self, instance):
- self.instances[instance.idx] = instance
-
- def getInstance(self, idx):
- return self.instances.get(idx)
-
- def getInstances(self):
- return self.instances.values()
-
- def getInstanceByDom(self, dom):
- for inst in self.instances.values():
- if inst.dom == dom:
- return inst
- return None
-
- def delInstance(self, instance):
- #print 'ControllerFactory>delInstance>', instance.idx
- if instance.idx in self.instances:
- #print 'ControllerFactory>delInstance> remove', instance.idx
- del self.instances[instance.idx]
-
- def createInstance(self, dom, recreate=0):
- raise NotImplementedError()
-
- def instanceClosed(self, instance):
- #print 'ControllerFactory>instanceClosed>', instance.idx, instance
- self.delInstance(instance)
-
- def addDeferred(self):
- d = defer.Deferred()
- if self.timeout > 0:
- # The deferred will error if not called before timeout.
- d.setTimeout(self.timeout)
- self.dlist.append(d)
- return d
-
- def callDeferred(self, *args):
- if self.dlist:
- d = self.dlist.pop(0)
- d.callback(*args)
-
- def errDeferred(self, *args):
- if self.dlist:
- d = self.dlist.pop(0)
- d.errback(*args)
-
-class Controller(CtrlMsgRcvr):
- """Abstract class for a device controller attached to a domain.
- """
-
- def __init__(self, factory, dom):
- CtrlMsgRcvr.__init__(self)
- self.factory = factory
- self.dom = int(dom)
- self.channel = None
- self.idx = None
-
- def close(self):
- self.deregisterChannel()
- self.lostChannel()
-
- def lostChannel(self):
- #print 'Controller>lostChannel>', self, self.factory
- self.factory.instanceClosed(self)
-
-class Dev:
-
- def __init__(self, controller):
- self.controller = controller
- self.props = {}
-
- def setprop(self, k, v):
- self.props[k] = v
-
- def getprop(self, k, v=None):
- return self.props.get(k, v)
-
- def hasprop(self, k):
- return k in self.props
-
- def delprop(self, k):
- if k in self.props:
- del self.props[k]
-
- #def __repr__(self):
- # return str(self.sxpr())
-
- def sxpr(self):
- raise NotImplementedError()
-
-
+++ /dev/null
-import struct
-
-class Struct:
-
- maxDepth = 10
-
- base = ['x', 'B', 'H', 'I', 'L', 'Q', 'c', 'h', 'i', 'l', 'q', ]
-
- sizes = {'B': 1,
- 'H': 2,
- 'I': 4,
- 'L': 4,
- 'Q': 8,
- 'c': 1,
- 'h': 2,
- 'i': 4,
- 'l': 4,
- 'q': 8,
- 'x': 1,
- }
-
- formats = {
- 'int8' : 'B',
- 'int16' : 'H',
- 'int32' : 'I',
- 'int64' : 'Q',
- 'u8' : 'B',
- 'u16' : 'H',
- 'u32' : 'I',
- 'u64' : 'Q'
- }
-
- def typedef(self, name, val):
- self.formats[name] = val
-
- def struct(self, name, *f):
- self.typedef(name, StructInfo(self, f))
-
- def getType(self, name):
- return self.formats[name]
-
- def format(self, ty):
- d = 0
- f = ty
- while d < self.maxDepth:
- d += 1
- f = self.formats[f]
- if isinstance(f, StructInfo):
- return f.format()
- if f in self.base:
- return f
- return -1
-
- def alignedformat(self, ty):
- fmt = self.format(ty)
- #print 'alignedformat> %s |%s|' %(ty, fmt)
- afmt = self.align(fmt)
- #print 'alignedformat< %s |%s| |%s|' % (ty, fmt, afmt)
- return afmt
-
- def align(self, fmt):
- n1 = 0
- afmt = ''
- for a in fmt:
- n2 = self.getSize(a)
- m = n1 % n2
- if m:
- d = (n2 - m)
- afmt += 'x' * d
- n1 += d
- afmt += a
- n1 += n2
- return afmt
-
- def fmtsize(self, fmt):
- s = 0
- for f in fmt:
- s += self.getSize(f)
- return s
-
- def getSize(self, f):
- return self.sizes[f]
-
- def pack(self, ty, data):
- return self.getType(ty).pack(data)
-
- def unpack(self, ty, data):
- return self.getType(ty).unpack(data)
-
- def show(self):
- l = self.formats.keys()
- l.sort()
- for v in l:
- print "%-35s %-10s %s" % (v, self.format(v), self.alignedformat(v))
-
-
-class StructInfo:
-
- def __init__(self, s, f):
- self.fmt = None
- self.structs = s
- self.fields = f
-
- def alignedformat(self):
- if self.afmt: return self.afmt
- self.afmt = self.structs.align(self.format())
- return self.afmt
-
- def format(self):
- if self.fmt: return self.fmt
- fmt = ""
- for (ty, name) in self.fields:
- fmt += self.formatString(ty)
- self.fmt = fmt
- return fmt
-
- def formatString(self, ty):
- if ty in self.fields:
- ty = self.fields[ty]
- return self.structs.format(ty)
-
- def pack(self, *args):
- return struct.pack(self.alignedformat(), *args)
-
- def unpack(self, data):
- return struct.unpack(self.alignedformat(), data)
-
-types = Struct()
-
-types.typedef('short' , 'h')
-types.typedef('int' , 'i')
-types.typedef('long' , 'l')
-types.typedef('unsigned short', 'H')
-types.typedef('unsigned int' , 'I')
-types.typedef('unsigned long' , 'L')
-types.typedef('domid_t' , 'u64')
-types.typedef('blkif_vdev_t' , 'u16')
-types.typedef('blkif_pdev_t' , 'u16')
-types.typedef('blkif_sector_t', 'u64')
-
-types.struct('u8[6]',
- ('u8', 'a1'),
- ('u8', 'a2'),
- ('u8', 'a3'),
- ('u8', 'a4'),
- ('u8', 'a5'),
- ('u8', 'a6'))
-
-types.struct('blkif_fe_interface_status_changed_t',
- ('unsigned int', 'handle'),
- ('unsigned int', 'status'),
- ('unsigned int', 'evtchn'))
-
-types.struct('blkif_fe_driver_status_changed_t',
- ('unsigned int', 'status'),
- ('unsigned int', 'nr_interfaces'))
-
-types.struct('blkif_fe_interface_connect_t',
- ('unsigned int' , 'handle'),
- ('unsigned long', 'shmem_frame'))
-
-types.struct('blkif_fe_interface_disconnect_t',
- ('unsigned int', 'handle'))
-
-types.struct('blkif_extent_t',
- ('blkif_pdev_t' , 'device'),
- ('blkif_sector_t', 'sector_start'),
- ('blkif_sector_t', 'sector_length'))
-
-types.struct('blkif_be_create_t',
- ('domid_t' , 'domid'),
- ('unsigned int', 'blkif_handle'),
- ('unsigned int', 'status'))
-
-types.struct('blkif_be_destroy_t',
- ('domid_t' , 'domid'),
- ('unsigned int', 'blkif_handle'),
- ('unsigned int', 'status'))
-
-types.struct('blkif_be_connect_t',
- ('domid_t' , 'domid'),
- ('unsigned int' , 'blkif_handle'),
- ('unsigned int' , 'evtchn'),
- ('unsigned long', 'shmem_frame'),
- ('unsigned int' , 'status'))
-
-types.struct('blkif_be_disconnect_t',
- ('domid_t' , 'domid'),
- ('unsigned int', 'blkif_handle'),
- ('unsigned int', 'status'))
-
-types.struct('blkif_be_vbd_create_t',
- ('domid_t' , 'domid'), #Q
- ('unsigned int', 'blkif_handle'), #I
- ('blkif_vdev_t', 'vdevice'), #H
- ('int' , 'readonly'), #i
- ('unsigned int', 'status')) #I
-
-types.struct('blkif_be_vbd_destroy_t',
- ('domid_t' , 'domid'),
- ('unsigned int', 'blkif_handle'),
- ('blkif_vdev_t', 'vdevice'),
- ('unsigned int', 'status'))
-
-types.struct('blkif_be_vbd_grow_t',
- ('domid_t' , 'domid'), #Q
- ('unsigned int' , 'blkif_handle'), #I
- ('blkif_vdev_t' , 'vdevice'), #H
- ('blkif_extent_t', 'extent'), #HQQ
- ('unsigned int' , 'status')) #I
-
-types.struct('blkif_be_vbd_shrink_t',
- ('domid_t' , 'domid'),
- ('unsigned int', 'blkif_handle'),
- ('blkif_vdev_t', 'vdevice'),
- ('unsigned int', 'status'))
-
-types.struct('blkif_be_driver_status_changed_t',
- ('unsigned int', 'status'),
- ('unsigned int', 'nr_interfaces'))
-
-types.struct('netif_fe_interface_status_changed_t',
- ('unsigned int', 'handle'),
- ('unsigned int', 'status'),
- ('unsigned int', 'evtchn'),
- ('u8[6]', 'mac'))
-
-types.struct('netif_fe_driver_status_changed_t',
- ('unsigned int', 'status'),
- ('unsigned int', 'nr_interfaces'))
-
-types.struct('netif_fe_interface_connect_t',
- ('unsigned int', 'handle'),
- ('unsigned long', 'tx_shmem_frame'),
- ('unsigned long', 'rx_shmem_frame'))
-
-types.struct('netif_fe_interface_disconnect_t',
- ('unsigned int', 'handle'))
-
-types.struct('netif_be_create_t',
- ('domid_t' , 'domid'),
- ('unsigned int', 'netif_handle'),
- ('u8[6]' , 'mac'),
- ('unsigned int', 'status'))
-
-types.struct('netif_be_destroy_t',
- ('domid_t' , 'domid'),
- ('unsigned int', 'netif_handle'),
- ('unsigned int', 'status'))
-
-types.struct('netif_be_connect_t',
- ('domid_t' , 'domid'),
- ('unsigned int' , 'netif_handle'),
- ('unsigned int' , 'evtchn'),
- ('unsigned long', 'tx_shmem_frame'),
- ('unsigned long', 'rx_shmem_frame'),
- ('unsigned int' , 'status'))
-
-types.struct('netif_be_disconnect_t',
- ('domid_t' , 'domid'),
- ('unsigned int', 'netif_handle'),
- ('unsigned int', 'status'))
-
-types.struct('netif_be_driver_status_changed_t',
- ('unsigned int', 'status'),
- ('unsigned int', 'nr_interfaces'))
-
-if 1 or __name__ == "__main__":
- types.show()
+++ /dev/null
-import channel
-import controller
-from messages import *
-
-class DomainControllerFactory(controller.ControllerFactory):
- """Factory for creating domain controllers.
- """
-
- def createInstance(self, dom):
- d = DomainController(self, dom)
- self.addInstance(d)
- return d
-
- def getInstanceByDom(self, dom):
- for inst in self.instances.values():
- if inst.dom == dom:
- return inst
- inst = self.createInstance(dom)
- return inst
-
-
-class DomainController(controller.Controller):
- """Generic controller for a domain.
- """
-
- reasons = {'poweroff' : 'shutdown_poweroff_t',
- 'reboot' : 'shutdown_reboot_t',
- 'suspend' : 'shutdown_suspend_t' }
-
- def __init__(self, factory, dom):
- controller.Controller.__init__(self, factory, dom)
- self.majorTypes = [ CMSG_SHUTDOWN ]
- self.registerChannel()
- print 'DomainController>', self, self.channel, self.idx
-
- def shutdown(self, reason):
- msgtype = self.reasons.get(reason)
- if not msgtype:
- raise ValueError('invalid reason:' + reason)
- msg = packMsg(msgtype, {})
- self.writeRequest(msg)
+++ /dev/null
-import struct
-
-from xen.ext import xu
-
-DEBUG = 0
-
-""" All message formats.
-Added to incrementally for the various message types.
-See below.
-"""
-msg_formats = {}
-
-#============================================================================
-# Console message types.
-#============================================================================
-
-CMSG_CONSOLE = 0
-
-console_formats = { 'console_data': (CMSG_CONSOLE, 0) }
-
-msg_formats.update(console_formats)
-
-#============================================================================
-# Block interface message types.
-#============================================================================
-
-CMSG_BLKIF_BE = 1
-CMSG_BLKIF_FE = 2
-
-CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED = 0
-CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED = 32
-CMSG_BLKIF_FE_INTERFACE_CONNECT = 33
-CMSG_BLKIF_FE_INTERFACE_DISCONNECT = 34
-
-CMSG_BLKIF_BE_CREATE = 0
-CMSG_BLKIF_BE_DESTROY = 1
-CMSG_BLKIF_BE_CONNECT = 2
-CMSG_BLKIF_BE_DISCONNECT = 3
-CMSG_BLKIF_BE_VBD_CREATE = 4
-CMSG_BLKIF_BE_VBD_DESTROY = 5
-CMSG_BLKIF_BE_VBD_GROW = 6
-CMSG_BLKIF_BE_VBD_SHRINK = 7
-CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED = 32
-
-BLKIF_DRIVER_STATUS_DOWN = 0
-BLKIF_DRIVER_STATUS_UP = 1
-
-BLKIF_INTERFACE_STATUS_DESTROYED = 0 #/* Interface doesn't exist. */
-BLKIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */
-BLKIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */
-
-BLKIF_BE_STATUS_OKAY = 0
-BLKIF_BE_STATUS_ERROR = 1
-BLKIF_BE_STATUS_INTERFACE_EXISTS = 2
-BLKIF_BE_STATUS_INTERFACE_NOT_FOUND = 3
-BLKIF_BE_STATUS_INTERFACE_CONNECTED = 4
-BLKIF_BE_STATUS_VBD_EXISTS = 5
-BLKIF_BE_STATUS_VBD_NOT_FOUND = 6
-BLKIF_BE_STATUS_OUT_OF_MEMORY = 7
-BLKIF_BE_STATUS_EXTENT_NOT_FOUND = 8
-BLKIF_BE_STATUS_MAPPING_ERROR = 9
-
-blkif_formats = {
- 'blkif_be_connect_t':
- (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT),
-
- 'blkif_be_create_t':
- (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE),
-
- 'blkif_be_disconnect_t':
- (CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT),
-
- 'blkif_be_destroy_t':
- (CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY),
-
- 'blkif_be_vbd_create_t':
- (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE),
-
- 'blkif_be_vbd_grow_t':
- (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW),
-
- 'blkif_be_vbd_destroy_t':
- (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY),
-
- 'blkif_fe_interface_status_changed_t':
- (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED),
-
- 'blkif_fe_driver_status_changed_t':
- (CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED),
-
- 'blkif_fe_interface_connect_t':
- (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT),
-}
-
-msg_formats.update(blkif_formats)
-
-#============================================================================
-# Network interface message types.
-#============================================================================
-
-CMSG_NETIF_BE = 3
-CMSG_NETIF_FE = 4
-
-CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED = 0
-CMSG_NETIF_FE_DRIVER_STATUS_CHANGED = 32
-CMSG_NETIF_FE_INTERFACE_CONNECT = 33
-CMSG_NETIF_FE_INTERFACE_DISCONNECT = 34
-
-CMSG_NETIF_BE_CREATE = 0
-CMSG_NETIF_BE_DESTROY = 1
-CMSG_NETIF_BE_CONNECT = 2
-CMSG_NETIF_BE_DISCONNECT = 3
-CMSG_NETIF_BE_DRIVER_STATUS_CHANGED = 32
-
-NETIF_INTERFACE_STATUS_DESTROYED = 0 #/* Interface doesn't exist. */
-NETIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */
-NETIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */
-
-NETIF_DRIVER_STATUS_DOWN = 0
-NETIF_DRIVER_STATUS_UP = 1
-
-netif_formats = {
- 'netif_be_connect_t':
- (CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT),
-
- 'netif_be_create_t':
- (CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE),
-
- 'netif_be_disconnect_t':
- (CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT),
-
- 'netif_be_destroy_t':
- (CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY),
-
- 'netif_be_driver_status_changed_t':
- (CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED),
-
- 'netif_fe_driver_status_changed_t':
- (CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED),
-
- 'netif_fe_interface_connect_t':
- (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT),
-
- 'netif_fe_interface_status_changed_t':
- (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED),
- }
-
-msg_formats.update(netif_formats)
-
-#============================================================================
-CMSG_SHUTDOWN = 6
-
-CMSG_SHUTDOWN_POWEROFF = 0
-CMSG_SHUTDOWN_REBOOT = 1
-CMSG_SHUTDOWN_SUSPEND = 2
-
-STOPCODE_shutdown = 0
-STOPCODE_reboot = 1
-STOPCODE_suspend = 2
-
-shutdown_formats = {
- 'shutdown_poweroff_t':
- (CMSG_SHUTDOWN, CMSG_SHUTDOWN_POWEROFF),
-
- 'shutdown_reboot_t':
- (CMSG_SHUTDOWN, CMSG_SHUTDOWN_REBOOT),
-
- 'shutdown_suspend_t':
- (CMSG_SHUTDOWN, CMSG_SHUTDOWN_SUSPEND),
- }
-
-msg_formats.update(shutdown_formats)
-
-#============================================================================
-
-class Msg:
- pass
-
-def packMsg(ty, params):
- if DEBUG: print '>packMsg', ty, params
- (major, minor) = msg_formats[ty]
- args = {}
- for (k, v) in params.items():
- if k == 'mac':
- for i in range(0, 6):
- args['mac[%d]' % i] = v[i]
- else:
- args[k] = v
- if DEBUG:
- for (k, v) in args.items():
- print 'packMsg>', k, v, type(v)
- msgid = 0
- msg = xu.message(major, minor, msgid, args)
- return msg
-
-def unpackMsg(ty, msg):
- args = msg.get_payload()
- mac = [0, 0, 0, 0, 0, 0]
- macs = []
- for (k, v) in args.items():
- if k.startswith('mac['):
- macs += k
- i = int(k[4:5])
- mac[i] = v
- else:
- pass
- if macs:
- args['mac'] = mac
- for k in macs:
- del args[k]
- if DEBUG: print '<unpackMsg', ty, args
- return args
-
-def msgTypeName(ty, subty):
- for (name, info) in msg_formats.items():
- if info[0] == ty and info[1] == subty:
- return name
- return None
-
+++ /dev/null
-import random
-
-from twisted.internet import defer
-
-from xen.xend import sxp
-from xen.xend import PrettyPrint
-from xen.xend import Vifctl
-
-import channel
-import controller
-from messages import *
-
-class NetifControllerFactory(controller.ControllerFactory):
- """Factory for creating network interface controllers.
- Also handles the 'back-end' channel to the device driver domain.
- """
-
- def __init__(self):
- controller.ControllerFactory.__init__(self)
-
- self.majorTypes = [ CMSG_NETIF_BE ]
-
- self.subTypes = {
- CMSG_NETIF_BE_CREATE : self.recv_be_create,
- CMSG_NETIF_BE_CONNECT: self.recv_be_connect,
- CMSG_NETIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
- }
- self.attached = 1
- self.registerChannel()
-
- def createInstance(self, dom, recreate=0):
- """Create or find the network interface controller for a domain.
- """
- #print 'netif>createInstance> dom=', dom
- netif = self.getInstanceByDom(dom)
- if netif is None:
- netif = NetifController(self, dom)
- self.addInstance(netif)
- return netif
-
- def getDomainDevices(self, dom):
- netif = self.getInstanceByDom(dom)
- return (netif and netif.getDevices()) or []
-
- def getDomainDevice(self, dom, vif):
- netif = self.getInstanceByDom(dom)
- return (netif and netif.getDevice(vif)) or None
-
- def setControlDomain(self, dom, recreate=0):
- """Set the 'back-end' device driver domain.
- """
- if self.dom == dom: return
- self.deregisterChannel()
- if not recreate:
- self.attached = 0
- self.dom = dom
- self.registerChannel()
- #
- #if xend.netif.be_port.remote_dom != 0:
- # xend.netif.recovery = True
- # xend.netif.be_port = xend.main.port_from_dom(dom)
- #
-
- def getControlDomain(self):
- return self.dom
-
- def recv_be_create(self, msg, req):
- self.callDeferred(0)
-
- def recv_be_connect(self, msg, req):
- val = unpackMsg('netif_be_connect_t', msg)
- dom = val['domid']
- vif = val['netif_handle']
- netif = self.getInstanceByDom(dom)
- if netif:
- netif.send_interface_connected(vif)
- else:
- print "recv_be_connect> unknown vif=", vif
- pass
-
- def recv_be_driver_status_changed(self, msg, req):
- val = unpackMsg('netif_be_driver_status_changed_t', msg)
- status = val['status']
- if status == NETIF_DRIVER_STATUS_UP and not self.attached:
- # If we are not attached the driver domain was changed, and
- # this signals the new driver domain is ready.
- for netif in self.getInstances():
- netif.reattach_devices()
- self.attached = 1
-
-## pl = msg.get_payload()
-## status = pl['status']
-## if status == NETIF_DRIVER_STATUS_UP:
-## if xend.netif.recovery:
-## print "New netif backend now UP, notifying guests:"
-## for netif_key in interface.list.keys():
-## netif = interface.list[netif_key]
-## netif.create()
-## print " Notifying %d" % netif.dom
-## msg = xu.message(
-## CMSG_NETIF_FE,
-## CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0,
-## { 'handle' : 0, 'status' : 1 })
-## netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg)
-## print "Done notifying guests"
-## recovery = False
-
-class NetDev(controller.Dev):
- """Info record for a network device.
- """
-
- def __init__(self, ctrl, vif, mac):
- controller.Dev.__init__(self, ctrl)
- self.vif = vif
- self.mac = mac
- self.evtchn = None
- self.bridge = None
- self.ipaddr = []
-
- def sxpr(self):
- vif = str(self.vif)
- mac = self.get_mac()
- val = ['netdev', ['vif', vif], ['mac', mac]]
- if self.bridge:
- val.append(['bridge', self.bridge])
- if self.evtchn:
- val.append(['evtchn',
- self.evtchn['port1'],
- self.evtchn['port2']])
- return val
-
- def get_vifname(self):
- return "vif%d.%d" % (self.controller.dom, self.vif)
-
- def get_mac(self):
- return ':'.join(map(lambda x: "%x" % x, self.mac))
-
- def vifctl_params(self):
- return { 'mac' : self.get_mac(),
- 'bridge': self.bridge,
- 'ipaddr': self.ipaddr }
-
- def up(self, bridge=None, ipaddr=[]):
- self.bridge = bridge
- self.ipaddr = ipaddr
- Vifctl.up(self.get_vifname(), **self.vifctl_params())
-
- def down(self):
- Vifctl.down(self.get_vifname(), **self.vifctl_params())
-
- def destroy(self):
- def cb_destroy(val):
- self.controller.send_be_destroy(self.vif)
- print 'NetDev>destroy>', 'vif=', self.vif
- PrettyPrint.prettyprint(self.sxpr())
- self.down()
- d = self.controller.factory.addDeferred()
- d.addCallback(cb_destroy)
- self.controller.send_be_disconnect(self.vif)
- #self.controller.send_be_destroy(self.vif)
-
-
-class NetifController(controller.Controller):
- """Network interface controller. Handles all network devices for a domain.
- """
-
- def __init__(self, factory, dom):
- #print 'NetifController> dom=', dom
- controller.Controller.__init__(self, factory, dom)
- self.devices = {}
-
- self.majorTypes = [ CMSG_NETIF_FE ]
-
- self.subTypes = {
- CMSG_NETIF_FE_DRIVER_STATUS_CHANGED:
- self.recv_fe_driver_status_changed,
- CMSG_NETIF_FE_INTERFACE_CONNECT :
- self.recv_fe_interface_connect,
- }
- self.registerChannel()
- #print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx
-
- def sxpr(self):
- val = ['netif', ['dom', self.dom]]
- return val
-
- def randomMAC(self):
- # VIFs get a random MAC address with a "special" vendor id.
- #
- # NB. The vendor is currently an "obsolete" one that used to belong
- # to DEC (AA-00-00). Using it is probably a bit rude :-)
- #
- # NB2. The first bit of the first random octet is set to zero for
- # all dynamic MAC addresses. This may allow us to manually specify
- # MAC addresses for some VIFs with no fear of clashes.
- mac = [ 0xaa, 0x00, 0x00,
- random.randint(0x00, 0x7f),
- random.randint(0x00, 0xff),
- random.randint(0x00, 0xff) ]
- return mac
-
- def lostChannel(self):
- print 'NetifController>lostChannel>', 'dom=', self.dom
- #self.destroyDevices()
- controller.Controller.lostChannel(self)
-
- def getDevices(self):
- return self.devices.values()
-
- def getDevice(self, vif):
- return self.devices.get(vif)
-
- def addDevice(self, vif, vmac):
- if vmac is None:
- mac = self.randomMAC()
- else:
- mac = [ int(x, 16) for x in vmac.split(':') ]
- if len(mac) != 6: raise ValueError("invalid mac")
- #print "attach_device>", "vif=", vif, "mac=", mac
- dev = NetDev(self, vif, mac)
- self.devices[vif] = dev
- return dev
-
- def destroy(self):
- print 'NetifController>destroy>', 'dom=', self.dom
- self.destroyDevices()
-
- def destroyDevices(self):
- for dev in self.getDevices():
- dev.destroy()
-
- def attachDevice(self, vif, vmac, recreate=0):
- """Attach a network device.
- If vmac is None a random mac address is assigned.
-
- @param vif interface index
- @param vmac mac address (string)
- """
- self.addDevice(vif, vmac)
- if recreate:
- d = defer.Deferred()
- d.callback(self)
- else:
- d = self.factory.addDeferred()
- self.send_be_create(vif)
- return d
-
- def reattach_devices(self):
- """Reattach all devices when the back-end control domain has changed.
- """
- d = self.factory.addDeferred()
- self.send_be_create(vif)
- self.attach_fe_devices(0)
-
- def attach_fe_devices(self):
- for dev in self.devices.values():
- msg = packMsg('netif_fe_interface_status_changed_t',
- { 'handle' : dev.vif,
- 'status' : NETIF_INTERFACE_STATUS_DISCONNECTED,
- 'evtchn' : 0,
- 'mac' : dev.mac })
- self.writeRequest(msg)
-
- def recv_fe_driver_status_changed(self, msg, req):
- if not req: return
- msg = packMsg('netif_fe_driver_status_changed_t',
- { 'status' : NETIF_DRIVER_STATUS_UP,
- 'nr_interfaces' : len(self.devices) })
- self.writeRequest(msg)
- self.attach_fe_devices()
-
- def recv_fe_interface_connect(self, msg, req):
- val = unpackMsg('netif_fe_interface_connect_t', msg)
- dev = self.devices[val['handle']]
- dev.evtchn = channel.eventChannel(0, self.dom)
- msg = packMsg('netif_be_connect_t',
- { 'domid' : self.dom,
- 'netif_handle' : dev.vif,
- 'evtchn' : dev.evtchn['port1'],
- 'tx_shmem_frame' : val['tx_shmem_frame'],
- 'rx_shmem_frame' : val['rx_shmem_frame'] })
- self.factory.writeRequest(msg)
-
- def send_interface_connected(self, vif):
- dev = self.devices[vif]
- msg = packMsg('netif_fe_interface_status_changed_t',
- { 'handle' : dev.vif,
- 'status' : NETIF_INTERFACE_STATUS_CONNECTED,
- 'evtchn' : dev.evtchn['port2'],
- 'mac' : dev.mac })
- self.writeRequest(msg)
-
- def send_be_create(self, vif):
- dev = self.devices[vif]
- msg = packMsg('netif_be_create_t',
- { 'domid' : self.dom,
- 'netif_handle' : dev.vif,
- 'mac' : dev.mac })
- self.factory.writeRequest(msg)
-
- def send_be_disconnect(self, vif):
- dev = self.devices[vif]
- msg = packMsg('netif_be_disconnect_t',
- { 'domid' : self.dom,
- 'netif_handle' : dev.vif })
- self.factory.writeRequest(msg)
-
- def send_be_destroy(self, vif):
- print 'NetifController>send_be_destroy>', 'dom=', self.dom, 'vif=', vif
- PrettyPrint.prettyprint(self.sxpr())
- dev = self.devices[vif]
- del self.devices[vif]
- msg = packMsg('netif_be_destroy_t',
- { 'domid' : self.dom,
- 'netif_handle' : vif })
- self.factory.writeRequest(msg)
+++ /dev/null
-# The following parameters could be placed in a configuration file.
-PID_FILE = '/var/run/xend.pid'
-LOG_FILE = '/var/log/xend.log'
-USER = 'root'
-CONTROL_DIR = '/var/run/xend'
-MGMT_SOCK = 'xendsock' # relative to CONTROL_DIR
-EVENT_PORT = 8001
-
-CONSOLE_PORT_BASE = 9600
-
+++ /dev/null
-#!/usr/bin/python2
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-"""
-Input-driven parsing for s-expression (sxp) format.
-Create a parser: pin = Parser();
-Then call pin.input(buf) with your input.
-Call pin.input_eof() when done.
-Use pin.read() to see if a value has been parsed, pin.get_val()
-to get a parsed value. You can call ready and get_val at any time -
-you don't have to wait until after calling input_eof.
-
-"""
-from __future__ import generators
-
-import sys
-import types
-import errno
-import string
-from StringIO import StringIO
-
-__all__ = [
- "mime_type",
- "ParseError",
- "Parser",
- "atomp",
- "show",
- "show_xml",
- "elementp",
- "name",
- "attributes",
- "attribute",
- "children",
- "child",
- "child_at",
- "child0",
- "child1",
- "child2",
- "child3",
- "child4",
- "child_value",
- "has_id",
- "with_id",
- "child_with_id",
- "elements",
- "parse",
- ]
-
-mime_type = "application/sxp"
-
-escapes = {
- 'a': '\a',
- 'b': '\b',
- 't': '\t',
- 'n': '\n',
- 'v': '\v',
- 'f': '\f',
- 'r': '\r',
- '\\': '\\',
- '\'': '\'',
- '\"': '\"'}
-
-k_list_open = "("
-k_list_close = ")"
-k_attr_open = "@"
-k_eval = "!"
-
-escapes_rev = {}
-for k in escapes:
- escapes_rev[escapes[k]] = k
-
-class ParseError(StandardError):
-
- def __init__(self, parser, value):
- self.parser = parser
- self.value = value
-
- def __str__(self):
- return self.value
-
-class ParserState:
-
- def __init__(self, fn, parent=None):
- self.parent = parent
- self.buf = ''
- self.val = []
- self.delim = None
- self.fn = fn
-
- def push(self, fn):
- return ParserState(fn, parent=self)
-
-class Parser:
-
- def __init__(self):
- self.error = sys.stderr
- self.reset()
-
- def reset(self):
- self.val = []
- self.eof = 0
- self.err = 0
- self.line_no = 0
- self.char_no = 0
- self.state = None
-
- def push_state(self, fn):
- self.state = self.state.push(fn)
-
- def pop_state(self):
- val = self.state
- self.state = self.state.parent
- if self.state and self.state.fn == self.state_start:
- # Return to start state - produce the value.
- self.val += self.state.val
- self.state.val = []
- return val
-
- def in_class(self, c, s):
- return s.find(c) >= 0
-
- def in_space_class(self, c):
- return self.in_class(c, ' \t\n\v\f\r')
-
- def is_separator(self, c):
- return self.in_class(c, '{}()<>[]!;')
-
- def in_comment_class(self, c):
- return self.in_class(c, '#')
-
- def in_string_quote_class(self, c):
- return self.in_class(c, '"\'')
-
- def in_printable_class(self, c):
- return self.in_class(c, string.printable)
-
- def set_error_stream(self, error):
- self.error = error
-
- def has_error(self):
- return self.err > 0
-
- def at_eof(self):
- return self.eof
-
- def input_eof(self):
- self.eof = 1
- self.input_char(-1)
-
- def input(self, buf):
- if not buf or len(buf) == 0:
- self.input_eof()
- else:
- for c in buf:
- self.input_char(c)
-
- def input_char(self, c):
- if self.at_eof():
- pass
- elif c == '\n':
- self.line_no += 1
- self.char_no = 0
- else:
- self.char_no += 1
-
- if self.state is None:
- self.begin_start(None)
- self.state.fn(c)
-
- def ready(self):
- return len(self.val) > 0
-
- def get_val(self):
- v = self.val[0]
- self.val = self.val[1:]
- return v
-
- def get_all(self):
- return self.val
-
- def begin_start(self, c):
- self.state = ParserState(self.state_start)
-
- def end_start(self):
- self.val += self.state.val
- self.pop_state()
-
- def state_start(self, c):
- if self.at_eof():
- self.end_start()
- elif self.in_space_class(c):
- pass
- elif self.in_comment_class(c):
- self.begin_comment(c)
- elif c == k_list_open:
- self.begin_list(c)
- elif c == k_list_close:
- raise ParseError(self, "syntax error: "+c)
- elif self.in_string_quote_class(c):
- self.begin_string(c)
- elif self.in_printable_class(c):
- self.begin_atom(c)
- elif c == chr(4):
- # ctrl-D, EOT: end-of-text.
- self.input_eof()
- else:
- raise ParseError(self, "invalid character: code %d" % ord(c))
-
- def begin_comment(self, c):
- self.push_state(self.state_comment)
- self.state.buf += c
-
- def end_comment(self):
- self.pop_state()
-
- def state_comment(self, c):
- if c == '\n' or self.at_eof():
- self.end_comment()
- else:
- self.state.buf += c
-
- def begin_string(self, c):
- self.push_state(self.state_string)
- self.state.delim = c
-
- def end_string(self):
- val = self.state.buf
- self.state.parent.val.append(val)
- self.pop_state()
-
- def state_string(self, c):
- if self.at_eof():
- raise ParseError(self, "unexpected EOF")
- elif c == self.state.delim:
- self.end_string()
- elif c == '\\':
- self.push_state(self.state_escape)
- else:
- self.state.buf += c
-
- def state_escape(self, c):
- if self.at_eof():
- raise ParseError(self, "unexpected EOF")
- d = escapes.get(c)
- if d:
- self.state.parent.buf += d
- self.pop_state()
- elif c == 'x':
- self.state.fn = self.state_hex
- self.state.val = 0
- else:
- self.state.fn = self.state_octal
- self.state.val = 0
- self.input_char(c)
-
- def state_octal(self, c):
- def octaldigit(c):
- self.state.val *= 8
- self.state.val += ord(c) - ord('0')
- self.state.buf += c
- if self.state.val < 0 or self.state.val > 0xff:
- raise ParseError(self, "invalid octal escape: out of range " + self.state.buf)
- if len(self.state.buf) == 3:
- octaldone()
-
- def octaldone():
- d = chr(self.state.val)
- self.state.parent.buf += d
- self.pop_state()
-
- if self.at_eof():
- raise ParseError(self, "unexpected EOF")
- elif '0' <= c <= '7':
- octaldigit(c)
- elif len(self.buf):
- octaldone()
- self.input_char(c)
-
- def state_hex(self, c):
- def hexdone():
- d = chr(self.state.val)
- self.state.parent.buf += d
- self.pop_state()
-
- def hexdigit(c, d):
- self.state.val *= 16
- self.state.val += ord(c) - ord(d)
- self.state.buf += c
- if self.state.val < 0 or self.state.val > 0xff:
- raise ParseError(self, "invalid hex escape: out of range " + self.state.buf)
- if len(self.state.buf) == 2:
- hexdone()
-
- if self.at_eof():
- raise ParseError(self, "unexpected EOF")
- elif '0' <= c <= '9':
- hexdigit(c, '0')
- elif 'A' <= c <= 'F':
- hexdigit(c, 'A')
- elif 'a' <= c <= 'f':
- hexdigit(c, 'a')
- elif len(buf):
- hexdone()
- self.input_char(c)
-
- def begin_atom(self, c):
- self.push_state(self.state_atom)
- self.state.buf = c
-
- def end_atom(self):
- val = self.state.buf
- self.state.parent.val.append(val)
- self.pop_state()
-
- def state_atom(self, c):
- if self.at_eof():
- self.end_atom()
- elif (self.is_separator(c) or
- self.in_space_class(c) or
- self.in_comment_class(c)):
- self.end_atom()
- self.input_char(c)
- else:
- self.state.buf += c
-
- def begin_list(self, c):
- self.push_state(self.state_list)
-
- def end_list(self):
- val = self.state.val
- self.state.parent.val.append(val)
- self.pop_state()
-
- def state_list(self, c):
- if self.at_eof():
- raise ParseError(self, "unexpected EOF")
- elif c == k_list_close:
- self.end_list()
- else:
- self.state_start(c)
-
-def atomp(sxpr):
- if sxpr.isalnum() or sxpr == '@':
- return 1
- for c in sxpr:
- if c in string.whitespace: return 0
- if c in '"\'\\(){}[]<>$#&%^': return 0
- if c in string.ascii_letters: continue
- if c in string.digits: continue
- if c in '.-_:/~': continue
- return 0
- return 1
-
-def show(sxpr, out=sys.stdout):
- if isinstance(sxpr, types.ListType):
- out.write(k_list_open)
- i = 0
- for x in sxpr:
- if i: out.write(' ')
- show(x, out)
- i += 1
- out.write(k_list_close)
- elif isinstance(sxpr, types.StringType) and atomp(sxpr):
- out.write(sxpr)
- else:
- #out.write("'" + str(sxpr) + "'")
- out.write(repr(str(sxpr)))
-
-def show_xml(sxpr, out=sys.stdout):
- if isinstance(sxpr, types.ListType):
- element = name(sxpr)
- out.write('<%s' % element)
- for attr in attributes(sxpr):
- out.write(' %s=%s' % (attr[0], attr[1]))
- out.write('>')
- i = 0
- for x in children(sxpr):
- if i: out.write(' ')
- show_xml(x, out)
- i += 1
- out.write('</%s>' % element)
- elif isinstance(sxpr, types.StringType) and atomp(sxpr):
- out.write(sxpr)
- else:
- out.write(str(sxpr))
-
-def elementp(sxpr, elt=None):
- return (isinstance(sxpr, types.ListType)
- and len(sxpr)
- and (None == elt or sxpr[0] == elt))
-
-def name(sxpr):
- val = None
- if isinstance(sxpr, types.StringType):
- val = sxpr
- elif isinstance(sxpr, types.ListType) and len(sxpr):
- val = sxpr[0]
- return val
-
-def attributes(sxpr):
- val = []
- if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
- attr = sxpr[1]
- if elementp(attr, k_attr_open):
- val = attr[1:]
- return val
-
-def attribute(sxpr, key, val=None):
- for x in attributes(sxpr):
- if x[0] == key:
- val = x[1]
- break
- return val
-
-def children(sxpr, elt=None):
- val = []
- if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
- i = 1
- x = sxpr[i]
- if elementp(x, k_attr_open):
- i += 1
- val = sxpr[i : ]
- if elt:
- def iselt(x):
- return elementp(x, elt)
- val = filter(iselt, val)
- return val
-
-def child(sxpr, elt, val=None):
- for x in children(sxpr):
- if elementp(x, elt):
- val = x
- break
- return val
-
-def child_at(sxpr, index, val=None):
- kids = children(sxpr)
- if len(kids) > index:
- val = kids[index]
- return val
-
-def child0(sxpr, val=None):
- return child_at(sxpr, 0, val)
-
-def child1(sxpr, val=None):
- return child_at(sxpr, 1, val)
-
-def child2(sxpr, val=None):
- return child_at(sxpr, 2, val)
-
-def child3(sxpr, val=None):
- return child_at(sxpr, 3, val)
-
-def child4(sxpr, val=None):
- return child_at(sxpr, 4, val)
-
-def child_value(sxpr, elt, val=None):
- kid = child(sxpr, elt)
- if kid:
- val = child_at(kid, 0, val)
- return val
-
-def has_id(sxpr, id):
- """Test if an s-expression has a given id.
- """
- return attribute(sxpr, 'id') == id
-
-def with_id(sxpr, id, val=None):
- """Find the first s-expression with a given id, at any depth.
-
- sxpr s-exp or list
- id id
- val value if not found (default None)
-
- return s-exp or val
- """
- if isinstance(sxpr, types.ListType):
- for n in sxpr:
- if has_id(n, id):
- val = n
- break
- v = with_id(n, id)
- if v is None: continue
- val = v
- break
- return val
-
-def child_with_id(sxpr, id, val=None):
- """Find the first child with a given id.
-
- sxpr s-exp or list
- id id
- val value if not found (default None)
-
- return s-exp or val
- """
- if isinstance(sxpr, types.ListType):
- for n in sxpr:
- if has_id(n, id):
- val = n
- break
- return val
-
-def elements(sxpr, ctxt=None):
- """Generate elements (at any depth).
- Visit elements in pre-order.
- Values generated are (node, context)
- The context is None if there is no parent, otherwise
- (index, parent, context) where index is the node's index w.r.t its parent,
- and context is the parent's context.
-
- sxpr s-exp
-
- returns generator
- """
- yield (sxpr, ctxt)
- i = 0
- for n in children(sxpr):
- if isinstance(n, types.ListType):
- # Calling elements() recursively does not generate recursively,
- # it just returns a generator object. So we must iterate over it.
- for v in elements(n, (i, sxpr, ctxt)):
- yield v
- i += 1
-
-def to_string(sxpr):
- """Convert an sxpr to a string.
-
- sxpr sxpr
- returns string
- """
- io = StringIO()
- show(sxpr, io)
- io.seek(0)
- val = io.getvalue()
- io.close()
- return val
-
-def from_string(str):
- """Create an sxpr by parsing a string.
-
- str string
- returns sxpr
- """
- io = StringIO(str)
- return parse(io)
-
-def parse(io):
- """Completely parse all input from 'io'.
-
- io input file object
- returns list of values, None if incomplete
- raises ParseError on parse error
- """
- pin = Parser()
- while 1:
- buf = io.readline()
- pin.input(buf)
- if len(buf) == 0:
- break
- if pin.ready():
- val = pin.get_all()
- else:
- val = None
- return val
-
-
-if __name__ == '__main__':
- print ">main"
- pin = Parser()
- while 1:
- buf = sys.stdin.read(1024)
- #buf = sys.stdin.readline()
- pin.input(buf)
- while pin.ready():
- val = pin.get_val()
- print
- print '****** val=', val
- if len(buf) == 0:
- break
-
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-"""Domain creation.
-"""
-import string
-import sys
-
-from xen.xend import sxp
-from xen.xend import PrettyPrint
-from xen.xend.XendClient import server
-
-from xen.xm.opts import *
-
-gopts = Opts(use="""[options]
-
-Create a domain.
-""")
-
-gopts.opt('help', short='h',
- fn=set_true, default=0,
- use="Print this help.")
-
-gopts.opt('quiet', short='q',
- fn=set_true, default=0,
- use="Quiet.")
-
-gopts.opt('path', val='PATH',
- fn=set_value, default='.:/etc/xen',
- use="Search path for default scripts.")
-
-gopts.opt('defaults', short='f', val='FILE',
- fn=set_value, default='xmdefaults',
- use="Use the given default script.")
-
-gopts.opt('config', short='F', val='FILE',
- fn=set_value, default=None,
- use='Domain configuration to use (SXP).')
-
-gopts.opt('load', short='L', val='FILE',
- fn=set_value, default=None,
- use='Domain saved state to load.')
-
-gopts.opt('define', short='D', val='VAR=VAL',
- fn=set_var, default=None,
- use="""Set a variable before loading defaults, e.g. '-D vmid=3'
- to set vmid. May be repeated to set more thanone variable.""")
-
-gopts.opt('dryrun', short='n',
- fn=set_true, default=0,
- use="Dry run - print the config but don't create the domain.")
-
-gopts.opt('name', short='N', val='NAME',
- fn=set_value, default=None,
- use="Domain name.")
-
-gopts.opt('console', short='c',
- fn=set_true, default=0,
- use="Connect to console after domain is created.")
-
-gopts.opt('kernel', short='k', val='FILE',
- fn=set_value, default=None,
- use="Path to kernel image.")
-
-gopts.opt('ramdisk', short='r', val='FILE',
- fn=set_value, default='',
- use="Path to ramdisk.")
-
-gopts.opt('builder', short='b', val='FUNCTION',
- fn=set_value, default='linux',
- use="Function to use to build the domain.")
-
-gopts.opt('memory', short='m', val='MEMORY',
- fn=set_value, default=128,
- use="Domain memory in MB.")
-
-gopts.opt('blkif',
- fn=set_true, default=0,
- use="Make the domain a block device backend.")
-
-gopts.opt('netif',
- fn=set_true, default=0,
- use="Make the domain a network interface backend.")
-
-gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE',
- fn=append_value, default=[],
- use="""Add a disk device to a domain. The physical device is DEV, which
- is exported to the domain as VDEV. The disk is read-only if MODE
- is 'r', read-write if MODE is 'w'.
- The option may be repeated to add more than one disk.
- """)
-
-gopts.opt('pci', val='BUS,DEV,FUNC',
- fn=append_value, default=[],
- use="""Add a PCI device to a domain, using given params (in hex).
- For example '-pci c0,02,1a'.
- The option may be repeated to add more than one pci device.
- """)
-
-gopts.opt('ipaddr', short='i', val="IPADDR",
- fn=append_value, default=[],
- use="Add an IP address to the domain.")
-
-gopts.opt('vif', val="mac=MAC,bridge=BRIDGE",
- fn=append_value, default=[],
- use="""Add a network interface with the given MAC address and bridge.
- If mac is not specified a random MAC address is used.
- If bridge is not specified the default bridge is used.
- This option may be repeated to add more than one vif.
- Specifying vifs will increase the number of interfaces as needed.
- """)
-
-gopts.opt('nics', val="NUM",
- fn=set_int, default=1,
- use="""Set the number of network interfaces.
- Use the vif option to define interface parameters, otherwise
- defaults are used. Specifying vifs will increase the
- number of interfaces as needed.
- """)
-
-gopts.opt('root', short='R', val='DEVICE',
- fn=set_value, default='',
- use="""Set the root= parameter on the kernel command line.
- Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
-
-gopts.opt('extra', short='E', val="ARGS",
- fn=set_value, default='',
- use="Set extra arguments to append to the kernel command line.")
-
-gopts.opt('ip', short='I', val='IPADDR',
- fn=set_value, default='',
- use="Set the kernel IP interface address.")
-
-gopts.opt('gateway', val="IPADDR",
- fn=set_value, default='',
- use="Set the kernel IP gateway.")
-
-gopts.opt('netmask', val="MASK",
- fn=set_value, default = '',
- use="Set the kernel IP netmask.")
-
-gopts.opt('hostname', val="NAME",
- fn=set_value, default='',
- use="Set the kernel IP hostname.")
-
-gopts.opt('interface', val="INTF",
- fn=set_value, default="eth0",
- use="Set the kernel IP interface name.")
-
-gopts.opt('dhcp', val="off|dhcp",
- fn=set_value, default='off',
- use="Set the kernel dhcp option.")
-
-gopts.opt('nfs_server', val="IPADDR",
- fn=set_value, default=None,
- use="Set the address of the NFS server for NFS root.")
-
-gopts.opt('nfs_root', val="PATH",
- fn=set_value, default=None,
- use="Set the path of the root NFS directory.")
-
-def strip(pre, s):
- """Strip prefix 'pre' if present.
- """
- if s.startswith(pre):
- return s[len(pre):]
- else:
- return s
-
-def configure_image(config, opts):
- """Create the image config.
- """
- config_image = [ opts.builder ]
- config_image.append([ 'kernel', os.path.abspath(opts.kernel) ])
- if opts.ramdisk:
- config_image.append([ 'ramdisk', os.path.abspath(opts.ramdisk) ])
- if opts.cmdline_ip:
- cmdline_ip = strip('ip=', opts.cmdline_ip)
- config_image.append(['ip', cmdline_ip])
- if opts.root:
- cmdline_root = strip('root=', opts.root)
- config_image.append(['root', cmdline_root])
- if opts.extra:
- config_image.append(['args', opts.extra])
- config.append(['image', config_image ])
-
-def configure_disks(config_devs, opts):
- """Create the config for disks (virtual block devices).
- """
- for (uname, dev, mode) in opts.disk:
- config_vbd = ['vbd',
- ['uname', uname],
- ['dev', dev ],
- ['mode', mode ] ]
- config_devs.append(['device', config_vbd])
-
-def configure_pci(config_devs, opts):
- """Create the config for pci devices.
- """
- for (bus, dev, func) in opts.pci:
- config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
- config_devs.append(['device', config_pci])
-
-def configure_vifs(config_devs, opts):
- """Create the config for virtual network interfaces.
- """
- vifs = opts.vif
- vifs_n = max(opts.nics, len(vifs))
-
- for idx in range(0, vifs_n):
- if idx < len(vifs):
- d = vifs[idx]
- mac = d.get('mac')
- bridge = d.get('bridge')
- else:
- mac = None
- bridge = None
- config_vif = ['vif']
- if mac:
- config_vif.append(['mac', mac])
- if bridge:
- config_vif.append(['bridge', bridge])
- config_devs.append(['device', config_vif])
-
-def configure_vfr(config, opts):
- if not opts.ipaddr: return
- config_vfr = ['vfr']
- idx = 0 # No way of saying which IP is for which vif?
- for ip in opts.ipaddr:
- config_vfr.append(['vif', ['id', idx], ['ip', ip]])
- config.append(config_vfr)
-
-
-def make_config(opts):
- """Create the domain configuration.
- """
-
- config = ['vm',
- ['name', opts.name ],
- ['memory', opts.memory ] ]
- if opts.cpu:
- config.append(['cpu', opts.cpu])
- if opts.blkif:
- config.append(['backend', ['blkif']])
- if opts.netif:
- config.append(['backend', ['netif']])
-
- configure_image(config, opts)
- config_devs = []
- configure_disks(config_devs, opts)
- configure_pci(config_devs, opts)
- configure_vifs(config_devs, opts)
- config += config_devs
- return config
-
-def preprocess_disk(opts):
- if not opts.disk: return
- disk = []
- for v in opts.disk:
- d = v.split(',')
- if len(d) != 3:
- opts.err('Invalid disk specifier: ' + v)
- disk.append(d)
- opts.disk = disk
-
-def preprocess_pci(opts):
- if not opts.pci: return
- pci = []
- for v in opts.pci:
- d = v.split(',')
- if len(d) != 3:
- opts.err('Invalid pci specifier: ' + v)
- # Components are in hex: add hex specifier.
- hexd = map(lambda v: '0x'+v, d)
- pci.append(hexd)
- opts.pci = pci
-
-def preprocess_vifs(opts):
- if not opts.vif: return
- vifs = []
- for vif in opts.vif:
- d = {}
- a = vif.split(',')
- for b in a:
- (k, v) = b.strip().split('=')
- k = k.strip()
- v = v.strip()
- if k not in ['mac', 'bridge']:
- opts.err('Invalid vif specifier: ' + vif)
- d[k] = v
- vifs.append(d)
- opts.vif = vifs
-
-def preprocess_ip(opts):
- setip = (opts.hostname or opts.netmask
- or opts.gateway or opts.dhcp or opts.interface)
- if not setip: return
- #if not opts
- ip = (opts.ip
- + ':'
- + ':' + opts.gateway
- + ':' + opts.netmask
- + ':' + opts.hostname
- + ':' + opts.interface
- + ':' + opts.dhcp)
- opts.cmdline_ip = ip
-
-def preprocess_nfs(opts):
- if (opts.nfs_root or opts.nfs_server):
- if (not opts.nfs_root) or (not opts.nfs_server):
- opts.err('Must set nfs root and nfs server')
- else:
- return
- nfs = 'nfsroot=' + opts.nfs_server + ':' + opts.nfs_root
- opts.extra = nfs + ' ' + opts.extra
-
-def preprocess(opts):
- if not opts.kernel:
- opts.err("No kernel specified")
- preprocess_disk(opts)
- preprocess_pci(opts)
- preprocess_vifs(opts)
- preprocess_ip(opts)
- preprocess_nfs(opts)
-
-def make_domain(opts, config):
- """Create, build and start a domain.
- Returns: [int] the ID of the new domain.
- """
- if opts.vals.load:
- filename = os.path.abspath(opts.vals.load)
- dominfo = server.xend_domain_restore(filename, config)
- else:
- dominfo = server.xend_domain_create(config)
-
- dom = int(sxp.child_value(dominfo, 'id'))
- console_info = sxp.child(dominfo, 'console')
- if console_info:
- console_port = int(sxp.child_value(console_info, 'port'))
- else:
- console_port = None
-
- if server.xend_domain_unpause(dom) < 0:
- server.xend_domain_destroy(dom)
- opts.err("Failed to start domain %d" % dom)
- opts.info("Started domain %d, console on port %d"
- % (dom, console_port))
- return (dom, console_port)
-
-def main(argv):
- opts = gopts
- args = opts.parse(argv)
- if opts.vals.help:
- opts.usage()
- return
- if opts.vals.config:
- pass
- else:
- opts.load_defaults()
- preprocess(opts.vals)
- config = make_config(opts.vals)
- if opts.vals.dryrun:
- PrettyPrint.prettyprint(config)
- else:
- make_domain(opts, config)
-
-if __name__ == '__main__':
- main(sys.argv)
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-"""Grand unified management application for Xen.
-"""
-import os
-import os.path
-import sys
-from getopt import getopt
-
-from xen.xend import PrettyPrint
-from xen.xend import sxp
-from xen.xend.XendClient import server
-from xen.xm import create, shutdown
-
-class Prog:
- """Base class for sub-programs.
- """
-
- """Program group it belongs to"""
- group = 'all'
- """Program name."""
- name = '??'
- """Short program info."""
- info = ''
-
- def __init__(self, xm):
- self.xm = xm
-
- def err(self, msg):
- self.xm.err(msg)
-
- def help(self, args):
- self.shortHelp(args)
-
- def shortHelp(self, args):
- print "%-14s %s" % (self.name, self.info)
-
- def main(self, args):
- """Program main entry point.
- """
- pass
-
-
-class ProgUnknown(Prog):
-
- name = 'unknown'
- info = ''
-
- def help(self, args):
- self.xm.err("Unknown command: %s\nTry '%s help' for more information."
- % (args[0], self.xm.name))
-
- main = help
-
-class Xm:
- """Main application.
- """
-
- def __init__(self):
- self.name = 'xm'
- self.unknown = ProgUnknown(self)
- self.progs = {}
-
- def err(self, msg):
- print >>sys.stderr, "Error:", msg
- sys.exit(1)
-
- def main(self, args):
- """Main entry point. Dispatches to the progs.
- """
- self.name = args[0]
- if len(args) < 2:
- self.err("Missing command\nTry '%s help' for more information."
- % self.name)
- help = self.helparg(args)
- p = self.getprog(args[1], self.unknown)
- if help:
- p.help(args[1:])
- else:
- p.main(args[1:])
-
- def helparg(self, args):
- for a in args:
- if a in ['-h', '--help']:
- return 1
- return 0
-
- def prog(self, pklass):
- """Add a sub-program.
-
- pklass program class (Prog subclass)
- """
- p = pklass(self)
- self.progs[p.name] = p
- return p
-
- def getprog(self, name, val=None):
- """Get a sub-program.
- """
- return self.progs.get(name, val)
-
- def proglist(self):
- """Get a list of sub-programs, ordered by group.
- """
- groups = {}
- for p in self.progs.values():
- l = groups.get(p.group, [])
- l.append(p)
- groups[p.group] = l
- kl = groups.keys()
- kl.sort()
- pl = []
- for k in kl:
- l = groups[k]
- l.sort()
- pl += l
- return pl
-
-# Create the application object, then add the sub-program classes.
-xm = Xm()
-
-class ProgHelp(Prog):
-
- name = "help"
- info = "Print help."
-
- def help(self, args):
- if len(args) == 2:
- name = args[1]
- p = self.xm.getprog(name)
- if p:
- p.help(args[1:])
- else:
- print '%s: Unknown command: %s' % (self.name, name)
- else:
- for p in self.xm.proglist():
- p.shortHelp(args)
- print "\nTry '%s help CMD' for help on CMD" % self.xm.name
-
- main = help
-
-xm.prog(ProgHelp)
-
-class ProgCreate(Prog):
-
- group = 'domain'
- name = "create"
- info = """Create a domain."""
-
- def help(self, args):
- create.main([args[0], '-h'])
-
- def main(self, args):
- create.main(args)
-
-xm.prog(ProgCreate)
-
-class ProgSave(Prog):
- group = 'domain'
- name = "save"
- info = """Save domain state (and config) to file."""
-
- def help(self, args):
- print args[0], "DOM FILE"
- print """\nSave domain with id DOM to FILE."""
-
- def main(self, args):
- if len(args) < 3: self.err("%s: Missing arguments" % args[0])
- dom = args[1]
- savefile = os.path.abspath(args[2])
- server.xend_domain_save(dom, savefile)
-
-xm.prog(ProgSave)
-
-class ProgRestore(Prog):
- group = 'domain'
- name = "restore"
- info = """Create a domain from a saved state."""
-
- def help(self, args):
- print args[0], "FILE [CONFIG]"
- print "\nRestore a domain from FILE using configuration CONFIG."
-
- def main(self, help, args):
- if len(args) < 2: self.err("%s: Missing arguments" % args[0])
- savefile = os.path.abspath(args[1])
- if len(args) >= 3:
- configfile = os.path.abspath(args[2])
- else:
- configfile = None
- info = server.xend_domain_restore(savefile, configfile)
- PrettyPrint.prettyprint(info)
-
-xm.prog(ProgRestore)
-
-class ProgList(Prog):
- group = 'domain'
- name = "list"
- info = """List info about domains."""
-
- short_options = 'l'
- long_options = ['long']
-
- def help(self, args):
- if help:
- print args[0], '[options] [DOM...]'
- print """\nGet information about domains.
- Either all domains or the domains given.
-
- -l, --long Get more detailed information.
- """
- return
-
- def main(self, args):
- use_long = 0
- (options, params) = getopt(args[1:],
- self.short_options,
- self.long_options)
- n = len(params)
- for (k, v) in options:
- if k in ['-l', '--long']:
- use_long = 1
-
- if n == 0:
- doms = map(int, server.xend_domains())
- doms.sort()
- else:
- doms = map(int, params)
-
- if use_long:
- self.long_list(doms)
- else:
- self.brief_list(doms)
-
- def brief_list(self, doms):
- print 'Dom Name Mem(MB) CPU State Time(s)'
- for dom in doms:
- info = server.xend_domain(dom)
- d = {}
- d['dom'] = int(dom)
- d['name'] = sxp.child_value(info, 'name', '??')
- d['mem'] = int(sxp.child_value(info, 'memory', '0'))
- d['cpu'] = int(sxp.child_value(info, 'cpu', '0'))
- d['state'] = sxp.child_value(info, 'state', '??')
- d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
- print ("%(dom)-4d %(name)-16s %(mem)7d %(cpu)3d %(state)5s %(cpu_time)7.1f" % d)
-
- def long_list(self, doms):
- for dom in doms:
- info = server.xend_domain(dom)
- print '\nDomain %d' % dom
- PrettyPrint.prettyprint(info)
-
-xm.prog(ProgList)
-
-class ProgDestroy(Prog):
- group = 'domain'
- name = "destroy"
- info = """Terminate a domain immediately."""
-
- def help(self, args):
- print args[0], 'DOM'
- print '\nTerminate domain DOM immediately.'
-
- def main(self, args):
- if len(args) < 2: self.err("%s: Missing domain" % args[0])
- dom = args[1]
- server.xend_domain_destroy(dom)
-
-xm.prog(ProgDestroy)
-
-class ProgShutdown(Prog):
- group = 'domain'
- name = "shutdown"
- info = """Shutdown a domain."""
-
- def help(self, args):
- shutdown.main([args[0], '-h'])
-
- def main(self, args):
- shutdown.main(args)
-
-xm.prog(ProgShutdown)
-
-class ProgPause(Prog):
- group = 'domain'
- name = "pause"
- info = """Pause execution of a domain."""
-
- def help(self, args):
- print args[0], 'DOM'
- print '\nPause execution of domain DOM.'
-
- def main(self, args):
- if len(args) < 2: self.err("%s: Missing domain" % args[0])
- dom = args[1]
- server.xend_domain_pause(dom)
-
-xm.prog(ProgPause)
-
-class ProgUnpause(Prog):
- group = 'domain'
- name = "unpause"
- info = """Unpause a paused domain."""
-
- def help(self, args):
- print args[0], 'DOM'
- print '\nUnpause execution of domain DOM.'
-
- def main(self, args):
- if len(args) < 2: self.err("%s: Missing domain" % args[0])
- dom = args[1]
- server.xend_domain_unpause(dom)
-
-xm.prog(ProgUnpause)
-
-class ProgPincpu(Prog):
- group = 'domain'
- name = "pincpu"
- info = """Pin a domain to a cpu. """
-
- def help(self, args):
- print args[0],'DOM CPU'
- print '\nPin domain DOM to cpu CPU.'
-
- def main(self, args):
- if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
- v = map(int, args[1:3])
- server.xend_domain_pincpu(*v)
-
-xm.prog(ProgPincpu)
-
-class ProgBvt(Prog):
- group = 'scheduler'
- name = "bvt"
- info = """Set BVT scheduler parameters."""
-
- def help(self, args):
- print args[0], "DOM MCUADV WARP WARPL WARPU"
- print '\nSet Borrowed Virtual Time scheduler parameters.'
-
- def main(self, args):
- if len(args) != 6: self.err("%s: Invalid argument(s)" % args[0])
- v = map(int, args[1:6])
- server.xend_domain_cpu_bvt_set(*v)
-
-xm.prog(ProgBvt)
-
-class ProgBvtslice(Prog):
- group = 'scheduler'
- name = "bvtslice"
- info = """Set the BVT scheduler slice."""
-
- def help(self, args):
- print args[0], 'SLICE'
- print '\nSet Borrowed Virtual Time scheduler slice.'
-
- def main(self, args):
- if len(args) < 2: self.err('%s: Missing slice' % args[0])
- server.xend_node_cpu_bvt_slice_set(slice)
-
-xm.prog(ProgBvtslice)
-
-class ProgAtropos(Prog):
- group = 'scheduler'
- name= "atropos"
- info = """Set atropos parameters."""
-
- def help(self, args):
- print args[0], "DOM PERIOD SLICE LATENCY XTRATIME"
- print "\nSet atropos parameters."
-
- def main(self, args):
- if len(args) != 5: self.err("%s: Invalid argument(s)" % args[0])
- v = map(int, args[1:5])
- server.xend_domain_cpu_atropos_set(*v)
-
-xm.prog(ProgAtropos)
-
-class ProgRrobin(Prog):
- group = 'scheduler'
- name = "rrobin"
- info = """Set round robin slice."""
-
- def help(self, args):
- print args[0], "SLICE"
- print "\nSet round robin scheduler slice."
-
- def main(self, args):
- if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
- rrslice = int(args[1])
- server.xend_node_rrobin_set(rrslice)
-
-xm.prog(ProgRrobin)
-
-class ProgInfo(Prog):
- group = 'host'
- name = "info"
- info = """Get information about the xen host."""
-
- def main(self, args):
- info = server.xend_node()
- for x in info[1:]:
- print "%-23s:" % x[0], x[1]
-
-xm.prog(ProgInfo)
-
-class ProgConsoles(Prog):
- group = 'console'
- name = "consoles"
- info = """Get information about domain consoles."""
-
- def main(self, args):
- l = server.xend_consoles()
- print "Dom Port Id"
- for x in l:
- info = server.xend_console(x)
- d = {}
- d['dom'] = sxp.child(info, 'dst', ['dst', '?', '?'])[1]
- d['port'] = sxp.child_value(info, 'port', '?')
- d['id'] = sxp.child_value(info, 'id', '?')
- print "%(dom)3s %(port)4s %(id)3s" % d
-
-xm.prog(ProgConsoles)
-
-class ProgConsole(Prog):
- group = 'console'
- name = "console"
- info = """Open a console to a domain."""
-
- def help(self, args):
- print "console DOM"
- print "\nOpen a console to domain DOM."
-
- def main(self, args):
- if len(args) < 2: self.err("%s: Missing domain" % args[0])
- dom = args[1]
- info = server.xend_domain(dom)
- console = sxp.child(info, "console")
- if not console:
- self.err("No console information")
- port = sxp.child_value(console, "port")
- from xen.util import console_client
- console_client.connect("localhost", int(port))
-
-xm.prog(ProgConsole)
-
-def main(args):
- xm.main(args)
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-"""Object-oriented command-line option support.
-"""
-from getopt import getopt
-import os
-import os.path
-import sys
-import types
-
-class Opt:
- """An individual option.
- """
- def __init__(self, opts, name, short=None, long=None,
- val=None, fn=None, use=None, default=None):
- """Create an option.
-
- opts parent options object
- name name of the field it controls
- short short (1-char) command line switch (optional)
- long long command-line switch. Defaults to option name.
- val string used to print option args in help.
- If val is not specified the option has no arg.
- fn function to call when the option is specified.
- use usage (help) string
- default default value if not specified on command-line
- """
- self.opts = opts
- self.name = name
- self.short = short
- if long is None:
- long = name
- self.long = long
- self.val = val
- self.use = use
- self.default = default
- self.optkeys = []
- if self.short:
- self.optkeys.append('-' + self.short)
- if self.long:
- self.optkeys.append('--' + self.long)
- self.fn = fn
- self.specified_opt = None
- self.specified_val = None
- self.value = None
- self.set(default)
-
- def __repr__(self):
- return self.name + '=' + str(self.specified_val)
-
- __str__ = __repr__
-
- def set(self, value):
- """Set the option value.
- """
- self.opts.setopt(self.name, value)
-
- def get(self):
- """Get the option value.
- """
- return self.opts.getopt(self.name)
-
- def append(self, value):
- """Append a value to the option value.
- """
- v = self.get() or []
- v.append(value)
- self.set(v)
-
- def short_opt(self):
- """Short option spec.
- """
- if self.short:
- if self.val:
- return self.short + ':'
- else:
- return self.short
- else:
- return None
-
- def long_opt(self):
- """Long option spec.
- """
- if self.long:
- if self.val:
- return self.long + '='
- else:
- return self.long
- else:
- return None
-
- def show(self):
- sep = ''
- for x in self.optkeys:
- print sep, x,
- sep = ','
- if self.val:
- print self.val,
- print
- if self.use:
- print '\t',
- print self.use
- if self.val:
- print '\tDefault', self.default or 'None'
-
- def specify(self, k, v):
- """Specify the option. Called when the option is set
- from the command line.
-
- k option switch used
- v optional value given (if any)
- """
- if k in self.optkeys:
- if self.val is None and v:
- self.opts.err("Option '%s' does not take a value" % k)
- self.specified_opt = k
- self.specified_val = v
- if self.fn:
- self.fn(self, k, v)
- return 1
- else:
- return 0
-
- def specified(self):
- """Test whether the option has been specified: set
- from the command line.
- """
- return self.specified_opt
-
-class OptVals:
- """Class to hold option values.
- """
- pass
-
-class Opts:
- """Container for options.
- """
- def __init__(self, use=None):
- """Options constructor.
-
- use usage string
- """
- self.use = use
- # List of options.
- self.options = []
- # Options indexed by name.
- self.options_map = {}
- # Command-line arguments.
- self.argv = []
- # Option values.
- self.vals = OptVals()
- self.vals.quiet = 0
- # Variables for default scripts.
- self.vars = {}
-
- def __repr__(self):
- return '\n'.join(map(str, self.options))
-
- __str__ = __repr__
-
- def opt(self, name, **args):
- """Add an option.
-
- name option name
- **args keyword params for option constructor
- """
- x = Opt(self, name, **args)
- self.options.append(x)
- self.options_map[name] = x
- return x
-
- def setvar(self, var, val):
- """Set a default script variable.
- """
- self.vars[var] = val
-
- def getvar(self, var):
- """Get a default script variable.
- """
- return self.vars.get(var)
-
- def option(self, name):
- """Get an option (object).
- """
- return self.options_map.get(name)
-
- def setopt(self, name, val):
- """Set an option value.
- An option can also be set using 'opts.vals.name = val'.
- """
- setattr(self.vals, name, val)
-
- def getopt(self, name):
- """Get an option value.
- An option value can also be got using 'opts.vals.name'.
- """
- getattr(self.vals, name)
-
- def specified(self, name):
- """Test if an option has been specified.
- """
- opt = self.option(name)
- return opt and opt.specified()
-
- def err(self, msg):
- """Print an error to stderr and exit.
- """
- print >>sys.stderr, "Error:", msg
- sys.exit(1)
-
- def info(self, msg):
- """Print a message to stdout (unless quiet is set).
- """
- if self.vals.quiet: return
- print msg
-
- def warn(self, msg):
- """Print a warning to stdout.
- """
- print >>sys.stderr, "Warning:", msg
-
- def parse(self, argv):
- """Parse arguments argv using the options.
-
- return remaining arguments
- """
- self.argv = argv
- (vals, args) = getopt(argv[1:], self.short_opts(), self.long_opts())
- self.args = args
- for (k, v) in vals:
- for opt in self.options:
- if opt.specify(k, v): break
- else:
- print >>sys.stderr, "Error: Unknown option:", k
- self.usage()
- return args
-
- def short_opts(self):
- """Get short options specifier for getopt.
- """
- l = []
- for x in self.options:
- y = x.short_opt()
- if not y: continue
- l.append(y)
- return ''.join(l)
-
- def long_opts(self):
- """Get long options specifier for getopt.
- """
- l = []
- for x in self.options:
- y = x.long_opt()
- if not y: continue
- l.append(y)
- return l
-
- def usage(self):
- print 'Usage: ', self.argv[0], self.use or 'OPTIONS'
- for opt in self.options:
- opt.show()
-
- def load_defaults(self):
- """Load a defaults script. Assumes these options set:
- 'path' search path
- 'default' script name
- """
- for x in [ '' ] + self.vals.path.split(':'):
- if x:
- p = os.path.join(x, self.vals.defaults)
- else:
- p = self.vals.defaults
- if os.path.exists(p):
- self.load(p)
- break
- else:
- self.err("Cannot open defaults file %s" % self.vals.defaults)
-
- def load(self, defaults, help=0):
- """Load a defaults file. Local variables in the file
- are used to set options with the same names.
- Variables are not used to set options that are already specified.
- """
- # Create global and lobal dicts for the file.
- # Initialize locals to the vars.
- # Use exec to do the standard imports and
- # define variables we are passing to the script.
- globals = {}
- locals = {}
- locals.update(self.vars)
- cmd = '\n'.join(["import sys",
- "import os",
- "import os.path",
- "import xen.util.ip",
- "xm_file = '%s'" % defaults,
- "xm_help = %d" % help ])
- exec cmd in globals, locals
- execfile(defaults, globals, locals)
- if help: return
- # Extract the values set by the script and set the corresponding
- # options, if not set on the command line.
- vtypes = [ types.StringType,
- types.ListType,
- types.IntType,
- types.FloatType
- ]
- for (k, v) in locals.items():
- if self.specified(k): continue
- if not(type(v) in vtypes): continue
- self.setopt(k, v)
-
-def set_true(opt, k, v):
- """Set an option true."""
- opt.set(1)
-
-def set_false(opt, k, v):
- """Set an option false."""
- opt.set(0)
-
-def set_value(opt, k, v):
- """Set an option to a valoue."""
- opt.set(v)
-
-def set_int(opt, k, v):
- """Set an option to an integer value."""
- try:
- v = int(v)
- except:
- opt.opts.err('Invalid value: ' + str(v))
- opt.set(v)
-
-def append_value(opt, k, v):
- """Append a value to a list option."""
- opt.append(v)
-
-def set_var(opt, k, v):
- """Set a default script variable.
- """
- (var, val) = v.strip().split('=')
- opt.opts.setvar(var.strip(), val.strip())
-
+++ /dev/null
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-"""Domain shutdown.
-"""
-import string
-import sys
-import time
-
-from xen.xend.XendClient import server
-from xen.xm.opts import *
-
-gopts = Opts(use="""[options] [DOM]
-
-Shutdown one or more domains gracefully.""")
-
-gopts.opt('help', short='h',
- fn=set_true, default=0,
- use="Print this help.")
-
-gopts.opt('all', short='a',
- fn=set_true, default=0,
- use="Shutdown all domains.")
-
-gopts.opt('wait', short='w',
- fn=set_true, default=0,
- use='Wait for shutdown to complete.')
-
-gopts.opt('norestart', short='n',
- fn=set_true, default=0,
- use='Prevent domain restart.')
-
-def shutdown(opts, doms, wait):
- def domains():
- return [ int(a) for a in server.xend_domains() ]
- if doms == None: doms = domains()
- if 0 in doms:
- doms.remove(0)
- for d in doms:
- server.xend_domain_shutdown(d)
- if wait:
- while doms:
- alive = domains()
- dead = []
- for d in doms:
- if d in alive: continue
- dead.append(d)
- for d in dead:
- opts.info("Domain %d terminated" % d)
- doms.remove(d)
- time.sleep(1)
- opts.info("All domains terminated")
-
-def main_all(opts, args):
- shutdown(opts, None, opts.vals.wait)
-
-def main_dom(opts, args):
- if len(args) < 1: opts.err('Missing domain')
- dom = args[0]
- try:
- domid = int(dom)
- except:
- opts.err('Invalid domain: ' + dom)
- shutdown(opts, [ domid ], opts.vals.wait)
-
-def main(argv):
- opts = gopts
- args = opts.parse(argv)
- if opts.vals.help:
- opts.usage()
- return
- print 'shutdown.main>', len(args), args
- if opts.vals.all:
- main_all(opts, args)
- else:
- main_dom(opts, args)
-
+++ /dev/null
-
-from distutils.core import setup, Extension
-
-setup(name = 'xen',
- version = '1.0',
- description = 'Xen',
- author = 'Mike Wray',
- author_email = 'mike.wray@hp.com',
- packages = ['xen',
- 'xen.ext',
- 'xen.util',
- 'xen.xend',
- 'xen.xend.server',
- 'xen.xm',
- ],
- package_dir = { 'xen': 'lib' },
- )
+++ /dev/null
-#!/usr/bin/python
-# -*- mode: python; -*-
-#============================================================================
-# Xen vif control script.
-#
-# vifctl init [bridge=<bridge>] [interface=<interface>]
-#
-# Called when xend starts up. Default behaviour is to create <bridge>
-# and add <interface> to it, moving its IP address to <bridge> and adjusting routes.
-#
-# vifctl (up|down) vif=<vif> mac=<mac> [bridge=<bridge>] (ipaddr=<ipaddr>)*
-#
-# Called when a vif is brought up or down. Default behaviour is to add
-# the vif to <bridge> on up and remove it from the bridge on down.
-# If ipaddr is specified, iptables rules for the ip addresses are
-# added on up and removed on down. The bridge a vif is added to can
-# be set in the vm config.
-#
-# The default bridge is nbe-br.
-# The default interface is eth0.
-#
-#============================================================================
-
-import sys
-import types
-
-from xen.util import Brctl
-
-from xen.xend import XendRoot
-xroot = XendRoot.instance()
-
-class VifControl:
-
- prefix = 'vifctl_'
-
- DEFAULT_BRIDGE = 'nbe-br'
- DEFAULT_INTERFACE = 'eth0'
-
- def __init__(self):
- self.name = 'vifctl'
-
- def main(self, args):
- #print self.name, args
- if len(args) < 2:
- usage(args)
- self.name = args[0]
- cmd = self.prefix + args[1]
- meth = getattr(self, cmd, self.unknown)
- meth(args[1:])
-
- def usage(self, args, out=sys.stderr):
- print >>out, 'Missing command, try \n%s help' % self.name
-
- def unknown(self, args, out=sys.stderr):
- print >>out, 'Unknown command:', args[1]
- self.help(out=out)
- sys.exit(1)
-
- def help(self, out=sys.stdout):
- print >>out, 'Commands are:',
- for x in vars(self):
- if x.startswith(prefix):
- cmd = x[len(prefix):]
- print >>out, cmd,
- print >>out
-
- def getparams(self, d, args, req=[]):
- """Parse args of the form 'key=val'. Valid keys are the ones
- in the dict 'd' passed in. If entries in 'd' have list values the
- values of the keys are appended.
-
- If 'req' is specified it is a list of required keys.
- """
- for x in args:
- (k, v) = x.split('=')
- k = k.strip()
- v = v.strip()
- if k not in d:
- print >>sys.stderr, 'Invalid parameter: ', k
- sys.exit(1)
- vold = d[k]
- if isinstance(vold , types.ListType):
- d[k] = vold + v
- else:
- d[k] = v
- for x in req:
- if not d[x]:
- print >>sys.stderr, 'Missing parameter:', x
- sys.exit(1)
- return d
-
- def vifctl_help(self, args):
- self.help()
-
- def default_bridge(self):
- return xroot.get_config_value('bridge', self.DEFAULT_BRIDGE)
-
- def default_interface(self):
- return xroot.get_config_value('interface', self.DEFAULT_INTERFACE)
-
- def vifctl_init(self, args):
- """Entry point for 'vifctl init'.
- """
- d = { 'bridge' : self.default_bridge(),
- 'interface': self.default_interface() }
- params = self.getparams(d, args[1:])
- interface = params['interface']
- bridge = params['bridge']
- # Create bridge 'bridge'.
- Brctl.bridge_create(bridge)
- # Reconfigure so that 'interface' is added to 'bridge',
- # and 'bridge' has the IP address from 'interface'.
- Brctl.reconfigure(interface, bridge)
-
- def vifparams(self, args):
- d = { 'vif' : None,
- 'mac' : None,
- 'bridge': self.default_bridge(),
- 'ipaddr': [] }
- d = self.getparams(d, args, req=['vif', 'mac'])
- return d
-
- def vifctl_up(self, args):
- """Entry point for 'vifctl up'.
- """
- params = self.vifparams(args[1:])
- # Add the vif to its bridge.
- Brctl.vif_bridge_add(params)
- if params['ipaddr']:
- # Add iptables rules for the ip addresses.
- vif = params['vif']
- for ipaddr in params['ipaddr']:
- Brctl.vif_restrict_addr(vif, ipaddr)
-
- def vifctl_down(self, args):
- """Entry point for 'vifctl down'.
- """
- params = self.vifparams(args[1:])
- # Remove the vif from its bridge.
- Brctl.vif_bridge_rem(params)
- if params['ip']:
- # Remove iptables rules for the ip addresses.
- vif = params['vif']
- for ip in params['ip']:
- Brctl.vif_restrict_addr(vif, ip, delete=1)
-
-
-if __name__ == "__main__":
- VifControl().main(sys.argv)
+++ /dev/null
-#!/usr/bin/python
-# -*- mode: python; -*-
-# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
-
-"""Xen management daemon. Lives in /usr/sbin.
- Provides console server and HTTP management api.
-
- Run:
-
- xend start
-
- The daemon is stopped with:
-
- xend stop
-
- The daemon should reconnect to device control interfaces
- and recover its state when restarted.
-"""
-import os
-import sys
-from xen.xend.server import SrvDaemon
-
-def main():
- daemon = SrvDaemon.instance()
- if not sys.argv[1:]:
- print 'usage: %s {start|stop|restart}' % sys.argv[0]
- elif os.fork():
- pid, status = os.wait()
- return status >> 8
- elif sys.argv[1] == 'start':
- return daemon.start()
- elif sys.argv[1] == 'trace_start':
- return daemon.start(trace=1)
- elif sys.argv[1] == 'stop':
- return daemon.stop()
- elif sys.argv[1] == 'restart':
- return daemon.stop() or daemon.start()
- else:
- print 'not an option:', sys.argv[1]
- return 1
-
-if __name__ == '__main__':
- sys.exit(main())
+++ /dev/null
-#!/usr/bin/python
-# -*- mode: python; -*-
-import sys
-from xen.xm import main
-
-main.main(sys.argv)
+XEN_ROOT=../..
+include $(XEN_ROOT)/tools/Make.defs
+
CC = gcc
CFLAGS = -Wall -O3 -Werror
-CFLAGS += -I../../xen/include/hypervisor-ifs
-CFLAGS += -I../../linux-xen-sparse/include
-CFLAGS += -I../xu/lib
-CFLAGS += -I../lib
+
+CFLAGS += -I $(XEN_HYPERVISOR_IFS)
+CFLAGS += -I $(XEN_LINUX_INCLUDE)
+CFLAGS += -I $(XEN_XC)
+CFLAGS += -I $(XEN_XU)
+CFLAGS += -I $(XEN_LIBXC)
+CFLAGS += -I $(XEN_LIBXUTIL)
HDRS = $(wildcard *.h)
OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
$(RM) *.a *.so *.o *.rpm $(BIN)
%: %.c $(HDRS) Makefile
- $(CC) $(CFLAGS) -o $@ $< -L../xc/lib -lxc
+ $(CC) $(CFLAGS) -o $@ $< -L$(XEN_LIBXC) -lxc
#include <argp.h>
#include <signal.h>
-#include "../xc/lib/xc_private.h"
+#include "xc_private.h"
/* from xen/include/hypervisor-ifs */
#include <trace.h>
+++ /dev/null
-
-all:
- python setup.py build
-
-install: all
- if [ "$(prefix)" = "" ]; then \
- python setup.py install; \
- elif [ "$(dist)" = "yes" ]; then \
- python setup.py install --home="$(prefix)"; \
- else \
- python setup.py install --root="$(prefix)"; \
- fi
-
-clean:
- rm -rf build *.pyc *.pyo *.a *.so *.o *~ *.rpm
+++ /dev/null
-/******************************************************************************
- * domain_controller.h
- *
- * Interface to server controller (e.g., 'xend'). This header file defines the
- * interface that is shared with guest OSes.
- *
- * Copyright (c) 2004, K A Fraser
- */
-
-#ifndef __DOMAIN_CONTROLLER_H__
-#define __DOMAIN_CONTROLLER_H__
-
-
-#ifndef BASIC_START_INFO
-#error "Xen header file hypervisor-if.h must already be included here."
-#endif
-
-
-/*
- * EXTENDED BOOTSTRAP STRUCTURE FOR NEW DOMAINS.
- */
-
-typedef struct {
- BASIC_START_INFO;
- u16 domain_controller_evtchn; /* 320 */
-} PACKED extended_start_info_t; /* 322 bytes */
-#define SIF_BLK_BE_DOMAIN (1<<4) /* Is this a block backend domain? */
-#define SIF_NET_BE_DOMAIN (1<<5) /* Is this a net backend domain? */
-
-
-/*
- * Reason codes for SCHEDOP_shutdown. These are opaque to Xen but may be
- * interpreted by control software to determine the appropriate action. These
- * are only really advisories: the controller can actually do as it likes.
- */
-#define SHUTDOWN_poweroff 0 /* Domain exited normally. Clean up and kill. */
-#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */
-#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */
-
-
-/*
- * CONTROLLER MESSAGING INTERFACE.
- */
-
-typedef struct {
- u8 type; /* 0: echoed in response */
- u8 subtype; /* 1: echoed in response */
- u8 id; /* 2: echoed in response */
- u8 length; /* 3: number of bytes in 'msg' */
- u8 msg[60]; /* 4: type-specific message data */
-} PACKED control_msg_t; /* 64 bytes */
-
-#define CONTROL_RING_SIZE 8
-typedef u32 CONTROL_RING_IDX;
-#define MASK_CONTROL_IDX(_i) ((_i)&(CONTROL_RING_SIZE-1))
-
-typedef struct {
- control_msg_t tx_ring[CONTROL_RING_SIZE]; /* 0: guest -> controller */
- control_msg_t rx_ring[CONTROL_RING_SIZE]; /* 512: controller -> guest */
- CONTROL_RING_IDX tx_req_prod, tx_resp_prod; /* 1024, 1028 */
- CONTROL_RING_IDX rx_req_prod, rx_resp_prod; /* 1032, 1036 */
-} PACKED control_if_t; /* 1040 bytes */
-
-/*
- * Top-level command types.
- */
-#define CMSG_CONSOLE 0 /* Console */
-#define CMSG_BLKIF_BE 1 /* Block-device backend */
-#define CMSG_BLKIF_FE 2 /* Block-device frontend */
-#define CMSG_NETIF_BE 3 /* Network-device backend */
-#define CMSG_NETIF_FE 4 /* Network-device frontend */
-#define CMSG_SHUTDOWN 6 /* Shutdown messages */
-
-
-/******************************************************************************
- * CONSOLE DEFINITIONS
- */
-
-/*
- * Subtypes for console messages.
- */
-#define CMSG_CONSOLE_DATA 0
-
-
-/******************************************************************************
- * BLOCK-INTERFACE FRONTEND DEFINITIONS
- */
-
-/* Messages from domain controller to guest. */
-#define CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED 0
-
-/* Messages from guest to domain controller. */
-#define CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED 32
-#define CMSG_BLKIF_FE_INTERFACE_CONNECT 33
-#define CMSG_BLKIF_FE_INTERFACE_DISCONNECT 34
-
-/* These are used by both front-end and back-end drivers. */
-#define blkif_vdev_t u16
-#define blkif_pdev_t u16
-#define blkif_sector_t u64
-
-/*
- * CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED:
- * Notify a guest about a status change on one of its block interfaces.
- * If the interface is DESTROYED or DOWN then the interface is disconnected:
- * 1. The shared-memory frame is available for reuse.
- * 2. Any unacknowledged messgaes pending on the interface were dropped.
- */
-#define BLKIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */
-#define BLKIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */
-#define BLKIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */
-typedef struct {
- u32 handle; /* 0 */
- u32 status; /* 4 */
- u16 evtchn; /* 8: (only if status == BLKIF_INTERFACE_STATUS_CONNECTED). */
-} PACKED blkif_fe_interface_status_changed_t; /* 10 bytes */
-
-/*
- * CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED:
- * Notify the domain controller that the front-end driver is DOWN or UP.
- * When the driver goes DOWN then the controller will send no more
- * status-change notifications. When the driver comes UP then the controller
- * will send a notification for each interface that currently exists.
- * If the driver goes DOWN while interfaces are still UP, the domain
- * will automatically take the interfaces DOWN.
- */
-#define BLKIF_DRIVER_STATUS_DOWN 0
-#define BLKIF_DRIVER_STATUS_UP 1
-typedef struct {
- /* IN */
- u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */
- /* OUT */
- /*
- * Tells driver how many interfaces it should expect to immediately
- * receive notifications about.
- */
- u32 nr_interfaces; /* 4 */
-} PACKED blkif_fe_driver_status_changed_t; /* 8 bytes */
-
-/*
- * CMSG_BLKIF_FE_INTERFACE_CONNECT:
- * If successful, the domain controller will acknowledge with a
- * STATUS_CONNECTED message.
- */
-typedef struct {
- u32 handle; /* 0 */
- u32 __pad;
- memory_t shmem_frame; /* 8 */
- MEMORY_PADDING;
-} PACKED blkif_fe_interface_connect_t; /* 16 bytes */
-
-/*
- * CMSG_BLKIF_FE_INTERFACE_DISCONNECT:
- * If successful, the domain controller will acknowledge with a
- * STATUS_DISCONNECTED message.
- */
-typedef struct {
- u32 handle; /* 0 */
-} PACKED blkif_fe_interface_disconnect_t; /* 4 bytes */
-
-
-/******************************************************************************
- * BLOCK-INTERFACE BACKEND DEFINITIONS
- */
-
-/* Messages from domain controller. */
-#define CMSG_BLKIF_BE_CREATE 0 /* Create a new block-device interface. */
-#define CMSG_BLKIF_BE_DESTROY 1 /* Destroy a block-device interface. */
-#define CMSG_BLKIF_BE_CONNECT 2 /* Connect i/f to remote driver. */
-#define CMSG_BLKIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */
-#define CMSG_BLKIF_BE_VBD_CREATE 4 /* Create a new VBD for an interface. */
-#define CMSG_BLKIF_BE_VBD_DESTROY 5 /* Delete a VBD from an interface. */
-#define CMSG_BLKIF_BE_VBD_GROW 6 /* Append an extent to a given VBD. */
-#define CMSG_BLKIF_BE_VBD_SHRINK 7 /* Remove last extent from a given VBD. */
-
-/* Messages to domain controller. */
-#define CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED 32
-
-/*
- * Message request/response definitions for block-device messages.
- */
-
-typedef struct {
- blkif_sector_t sector_start; /* 0 */
- blkif_sector_t sector_length; /* 8 */
- blkif_pdev_t device; /* 16 */
- u16 __pad; /* 18 */
-} PACKED blkif_extent_t; /* 20 bytes */
-
-/* Non-specific 'okay' return. */
-#define BLKIF_BE_STATUS_OKAY 0
-/* Non-specific 'error' return. */
-#define BLKIF_BE_STATUS_ERROR 1
-/* The following are specific error returns. */
-#define BLKIF_BE_STATUS_INTERFACE_EXISTS 2
-#define BLKIF_BE_STATUS_INTERFACE_NOT_FOUND 3
-#define BLKIF_BE_STATUS_INTERFACE_CONNECTED 4
-#define BLKIF_BE_STATUS_VBD_EXISTS 5
-#define BLKIF_BE_STATUS_VBD_NOT_FOUND 6
-#define BLKIF_BE_STATUS_OUT_OF_MEMORY 7
-#define BLKIF_BE_STATUS_EXTENT_NOT_FOUND 8
-#define BLKIF_BE_STATUS_MAPPING_ERROR 9
-
-/* This macro can be used to create an array of descriptive error strings. */
-#define BLKIF_BE_STATUS_ERRORS { \
- "Okay", \
- "Non-specific error", \
- "Interface already exists", \
- "Interface not found", \
- "Interface is still connected", \
- "VBD already exists", \
- "VBD not found", \
- "Out of memory", \
- "Extent not found for VBD", \
- "Could not map domain memory" }
-
-/*
- * CMSG_BLKIF_BE_CREATE:
- * When the driver sends a successful response then the interface is fully
- * created. The controller will send a DOWN notification to the front-end
- * driver.
- */
-typedef struct {
- /* IN */
- domid_t domid; /* 0: Domain attached to new interface. */
- u32 blkif_handle; /* 4: Domain-specific interface handle. */
- /* OUT */
- u32 status; /* 8 */
-} PACKED blkif_be_create_t; /* 12 bytes */
-
-/*
- * CMSG_BLKIF_BE_DESTROY:
- * When the driver sends a successful response then the interface is fully
- * torn down. The controller will send a DESTROYED notification to the
- * front-end driver.
- */
-typedef struct {
- /* IN */
- domid_t domid; /* 0: Identify interface to be destroyed. */
- u32 blkif_handle; /* 4: ...ditto... */
- /* OUT */
- u32 status; /* 8 */
-} PACKED blkif_be_destroy_t; /* 12 bytes */
-
-/*
- * CMSG_BLKIF_BE_CONNECT:
- * When the driver sends a successful response then the interface is fully
- * connected. The controller will send a CONNECTED notification to the
- * front-end driver.
- */
-typedef struct {
- /* IN */
- domid_t domid; /* 0: Domain attached to new interface. */
- u32 blkif_handle; /* 4: Domain-specific interface handle. */
- memory_t shmem_frame; /* 8: Page cont. shared comms window. */
- MEMORY_PADDING;
- u32 evtchn; /* 16: Event channel for notifications. */
- /* OUT */
- u32 status; /* 20 */
-} PACKED blkif_be_connect_t; /* 24 bytes */
-
-/*
- * CMSG_BLKIF_BE_DISCONNECT:
- * When the driver sends a successful response then the interface is fully
- * disconnected. The controller will send a DOWN notification to the front-end
- * driver.
- */
-typedef struct {
- /* IN */
- domid_t domid; /* 0: Domain attached to new interface. */
- u32 blkif_handle; /* 4: Domain-specific interface handle. */
- /* OUT */
- u32 status; /* 8 */
-} PACKED blkif_be_disconnect_t; /* 12 bytes */
-
-/* CMSG_BLKIF_BE_VBD_CREATE */
-typedef struct {
- /* IN */
- domid_t domid; /* 0: Identify blkdev interface. */
- u32 blkif_handle; /* 4: ...ditto... */
- blkif_vdev_t vdevice; /* 8: Interface-specific id for this VBD. */
- u16 readonly; /* 10: Non-zero -> VBD isn't writeable. */
- /* OUT */
- u32 status; /* 12 */
-} PACKED blkif_be_vbd_create_t; /* 16 bytes */
-
-/* CMSG_BLKIF_BE_VBD_DESTROY */
-typedef struct {
- /* IN */
- domid_t domid; /* 0: Identify blkdev interface. */
- u32 blkif_handle; /* 4: ...ditto... */
- blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */
- u16 __pad; /* 10 */
- /* OUT */
- u32 status; /* 12 */
-} PACKED blkif_be_vbd_destroy_t; /* 16 bytes */
-
-/* CMSG_BLKIF_BE_VBD_GROW */
-typedef struct {
- /* IN */
- domid_t domid; /* 0: Identify blkdev interface. */
- u32 blkif_handle; /* 4: ...ditto... */
- blkif_extent_t extent; /* 8: Physical extent to append to VBD. */
- blkif_vdev_t vdevice; /* 28: Interface-specific id of the VBD. */
- u16 __pad; /* 30 */
- /* OUT */
- u32 status; /* 32 */
-} PACKED blkif_be_vbd_grow_t; /* 36 bytes */
-
-/* CMSG_BLKIF_BE_VBD_SHRINK */
-typedef struct {
- /* IN */
- domid_t domid; /* 0: Identify blkdev interface. */
- u32 blkif_handle; /* 4: ...ditto... */
- blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */
- u16 __pad; /* 10 */
- /* OUT */
- u32 status; /* 12 */
-} PACKED blkif_be_vbd_shrink_t; /* 16 bytes */
-
-/*
- * CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED:
- * Notify the domain controller that the back-end driver is DOWN or UP.
- * If the driver goes DOWN while interfaces are still UP, the controller
- * will automatically send DOWN notifications.
- */
-typedef struct {
- u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */
-} PACKED blkif_be_driver_status_changed_t; /* 4 bytes */
-
-
-/******************************************************************************
- * NETWORK-INTERFACE FRONTEND DEFINITIONS
- */
-
-/* Messages from domain controller to guest. */
-#define CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED 0
-
-/* Messages from guest to domain controller. */
-#define CMSG_NETIF_FE_DRIVER_STATUS_CHANGED 32
-#define CMSG_NETIF_FE_INTERFACE_CONNECT 33
-#define CMSG_NETIF_FE_INTERFACE_DISCONNECT 34
-
-/*
- * CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED:
- * Notify a guest about a status change on one of its network interfaces.
- * If the interface is DESTROYED or DOWN then the interface is disconnected:
- * 1. The shared-memory frame is available for reuse.
- * 2. Any unacknowledged messgaes pending on the interface were dropped.
- */
-#define NETIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */
-#define NETIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */
-#define NETIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */
-typedef struct {
- u32 handle; /* 0 */
- u32 status; /* 4 */
- u16 evtchn; /* 8: status == NETIF_INTERFACE_STATUS_CONNECTED */
- u8 mac[6]; /* 10: status == NETIF_INTERFACE_STATUS_CONNECTED */
-} PACKED netif_fe_interface_status_changed_t; /* 16 bytes */
-
-/*
- * CMSG_NETIF_FE_DRIVER_STATUS_CHANGED:
- * Notify the domain controller that the front-end driver is DOWN or UP.
- * When the driver goes DOWN then the controller will send no more
- * status-change notifications. When the driver comes UP then the controller
- * will send a notification for each interface that currently exists.
- * If the driver goes DOWN while interfaces are still UP, the domain
- * will automatically take the interfaces DOWN.
- */
-#define NETIF_DRIVER_STATUS_DOWN 0
-#define NETIF_DRIVER_STATUS_UP 1
-typedef struct {
- /* IN */
- u32 status; /* 0: NETIF_DRIVER_STATUS_??? */
- /* OUT */
- /*
- * Tells driver how many interfaces it should expect to immediately
- * receive notifications about.
- */
- u32 nr_interfaces; /* 4 */
-} PACKED netif_fe_driver_status_changed_t; /* 8 bytes */
-
-/*
- * CMSG_NETIF_FE_INTERFACE_CONNECT:
- * If successful, the domain controller will acknowledge with a
- * STATUS_CONNECTED message.
- */
-typedef struct {
- u32 handle; /* 0 */
- u32 __pad; /* 4 */
- memory_t tx_shmem_frame; /* 8 */
- MEMORY_PADDING;
- memory_t rx_shmem_frame; /* 16 */
- MEMORY_PADDING;
-} PACKED netif_fe_interface_connect_t; /* 24 bytes */
-
-/*
- * CMSG_NETIF_FE_INTERFACE_DISCONNECT:
- * If successful, the domain controller will acknowledge with a
- * STATUS_DISCONNECTED message.
- */
-typedef struct {
- u32 handle; /* 0 */
-} PACKED netif_fe_interface_disconnect_t; /* 4 bytes */
-
-
-/******************************************************************************
- * NETWORK-INTERFACE BACKEND DEFINITIONS
- */
-
-/* Messages from domain controller. */
-#define CMSG_NETIF_BE_CREATE 0 /* Create a new net-device interface. */
-#define CMSG_NETIF_BE_DESTROY 1 /* Destroy a net-device interface. */
-#define CMSG_NETIF_BE_CONNECT 2 /* Connect i/f to remote driver. */
-#define CMSG_NETIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */
-
-/* Messages to domain controller. */
-#define CMSG_NETIF_BE_DRIVER_STATUS_CHANGED 32
-
-/*
- * Message request/response definitions for net-device messages.
- */
-
-/* Non-specific 'okay' return. */
-#define NETIF_BE_STATUS_OKAY 0
-/* Non-specific 'error' return. */
-#define NETIF_BE_STATUS_ERROR 1
-/* The following are specific error returns. */
-#define NETIF_BE_STATUS_INTERFACE_EXISTS 2
-#define NETIF_BE_STATUS_INTERFACE_NOT_FOUND 3
-#define NETIF_BE_STATUS_INTERFACE_CONNECTED 4
-#define NETIF_BE_STATUS_OUT_OF_MEMORY 5
-#define NETIF_BE_STATUS_MAPPING_ERROR 6
-
-/* This macro can be used to create an array of descriptive error strings. */
-#define NETIF_BE_STATUS_ERRORS { \
- "Okay", \
- "Non-specific error", \
- "Interface already exists", \
- "Interface not found", \
- "Interface is still connected", \
- "Out of memory", \
- "Could not map domain memory" }
-
-/*
- * CMSG_NETIF_BE_CREATE:
- * When the driver sends a successful response then the interface is fully
- * created. The controller will send a DOWN notification to the front-end
- * driver.
- */
-typedef struct {
- /* IN */
- domid_t domid; /* 0: Domain attached to new interface. */
- u32 netif_handle; /* 4: Domain-specific interface handle. */
- u8 mac[6]; /* 8 */
- u16 __pad; /* 14 */
- /* OUT */
- u32 status; /* 16 */
-} PACKED netif_be_create_t; /* 20 bytes */
-
-/*
- * CMSG_NETIF_BE_DESTROY:
- * When the driver sends a successful response then the interface is fully
- * torn down. The controller will send a DESTROYED notification to the
- * front-end driver.
- */
-typedef struct {
- /* IN */
- domid_t domid; /* 0: Identify interface to be destroyed. */
- u32 netif_handle; /* 4: ...ditto... */
- /* OUT */
- u32 status; /* 8 */
-} PACKED netif_be_destroy_t; /* 12 bytes */
-
-/*
- * CMSG_NETIF_BE_CONNECT:
- * When the driver sends a successful response then the interface is fully
- * connected. The controller will send a CONNECTED notification to the
- * front-end driver.
- */
-typedef struct {
- /* IN */
- domid_t domid; /* 0: Domain attached to new interface. */
- u32 netif_handle; /* 4: Domain-specific interface handle. */
- memory_t tx_shmem_frame; /* 8: Page cont. tx shared comms window. */
- MEMORY_PADDING;
- memory_t rx_shmem_frame; /* 16: Page cont. rx shared comms window. */
- MEMORY_PADDING;
- u16 evtchn; /* 24: Event channel for notifications. */
- u16 __pad; /* 26 */
- /* OUT */
- u32 status; /* 28 */
-} PACKED netif_be_connect_t; /* 32 bytes */
-
-/*
- * CMSG_NETIF_BE_DISCONNECT:
- * When the driver sends a successful response then the interface is fully
- * disconnected. The controller will send a DOWN notification to the front-end
- * driver.
- */
-typedef struct {
- /* IN */
- domid_t domid; /* 0: Domain attached to new interface. */
- u32 netif_handle; /* 4: Domain-specific interface handle. */
- /* OUT */
- u32 status; /* 8 */
-} PACKED netif_be_disconnect_t; /* 12 bytes */
-
-/*
- * CMSG_NETIF_BE_DRIVER_STATUS_CHANGED:
- * Notify the domain controller that the back-end driver is DOWN or UP.
- * If the driver goes DOWN while interfaces are still UP, the domain
- * will automatically send DOWN notifications.
- */
-typedef struct {
- u32 status; /* 0: NETIF_DRIVER_STATUS_??? */
-} PACKED netif_be_driver_status_changed_t; /* 4 bytes */
-
-
-/******************************************************************************
- * SHUTDOWN DEFINITIONS
- */
-
-/*
- * Subtypes for shutdown messages.
- */
-#define CMSG_SHUTDOWN_POWEROFF 0 /* Clean shutdown (SHUTDOWN_poweroff). */
-#define CMSG_SHUTDOWN_REBOOT 1 /* Clean shutdown (SHUTDOWN_reboot). */
-#define CMSG_SHUTDOWN_SUSPEND 2 /* Create suspend info, then */
- /* SHUTDOWN_suspend. */
-
-#endif /* __DOMAIN_CONTROLLER_H__ */
+++ /dev/null
-/******************************************************************************
- * utils.c
- *
- * Copyright (c) 2004, K A Fraser
- */
-
-#include <Python.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/mman.h>
-#include <sys/poll.h>
-#include <netinet/in.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <signal.h>
-#include <xc.h>
-
-#include <hypervisor-if.h>
-#include "domain_controller.h"
-
-#include <asm-xen/proc_cmd.h>
-
-#define XENPKG "xen.ext.xu"
-
-/* Needed for Python versions earlier than 2.3. */
-#ifndef PyMODINIT_FUNC
-#define PyMODINIT_FUNC DL_EXPORT(void)
-#endif
-
-/* NB. The following should be kept in sync with the kernel's evtchn driver. */
-#define EVTCHN_DEV_NAME "/dev/xen/evtchn"
-#define EVTCHN_DEV_MAJOR 10
-#define EVTCHN_DEV_MINOR 200
-#define PORT_NORMAL 0x0000 /* A standard event notification. */
-#define PORT_EXCEPTION 0x8000 /* An exceptional notification. */
-#define PORTIDX_MASK 0x7fff /* Strip subtype to obtain port index. */
-/* /dev/xen/evtchn ioctls: */
-/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */
-#define EVTCHN_RESET _IO('E', 1)
-/* EVTCHN_BIND: Bind to teh specified event-channel port. */
-#define EVTCHN_BIND _IO('E', 2)
-/* EVTCHN_UNBIND: Unbind from the specified event-channel port. */
-#define EVTCHN_UNBIND _IO('E', 3)
-
-/* Size of a machine page frame. */
-#define PAGE_SIZE 4096
-
-
-/*
- * *********************** NOTIFIER ***********************
- */
-
-typedef struct {
- PyObject_HEAD;
- int evtchn_fd;
-} xu_notifier_object;
-
-static PyObject *xu_notifier_read(PyObject *self, PyObject *args)
-{
- xu_notifier_object *xun = (xu_notifier_object *)self;
- u16 v;
- int bytes;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- while ( (bytes = read(xun->evtchn_fd, &v, sizeof(v))) == -1 )
- {
- if ( errno == EINTR )
- continue;
- if ( errno == EAGAIN )
- goto none;
- return PyErr_SetFromErrno(PyExc_IOError);
- }
-
- if ( bytes == sizeof(v) )
- return Py_BuildValue("(i,i)", v&PORTIDX_MASK, v&~PORTIDX_MASK);
-
- none:
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *xu_notifier_unmask(PyObject *self, PyObject *args)
-{
- xu_notifier_object *xun = (xu_notifier_object *)self;
- u16 v;
- int idx;
-
- if ( !PyArg_ParseTuple(args, "i", &idx) )
- return NULL;
-
- v = (u16)idx;
-
- (void)write(xun->evtchn_fd, &v, sizeof(v));
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *xu_notifier_bind(PyObject *self, PyObject *args)
-{
- xu_notifier_object *xun = (xu_notifier_object *)self;
- int idx;
-
- if ( !PyArg_ParseTuple(args, "i", &idx) )
- return NULL;
-
- if ( ioctl(xun->evtchn_fd, EVTCHN_BIND, idx) != 0 )
- return PyErr_SetFromErrno(PyExc_IOError);
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *xu_notifier_unbind(PyObject *self, PyObject *args)
-{
- xu_notifier_object *xun = (xu_notifier_object *)self;
- int idx;
-
- if ( !PyArg_ParseTuple(args, "i", &idx) )
- return NULL;
-
- if ( ioctl(xun->evtchn_fd, EVTCHN_UNBIND, idx) != 0 )
- return PyErr_SetFromErrno(PyExc_IOError);
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *xu_notifier_fileno(PyObject *self, PyObject *args)
-{
- xu_notifier_object *xun = (xu_notifier_object *)self;
- return PyInt_FromLong(xun->evtchn_fd);
-}
-
-static PyMethodDef xu_notifier_methods[] = {
- { "read",
- (PyCFunction)xu_notifier_read,
- METH_VARARGS,
- "Read a (@port, @type) pair.\n" },
-
- { "unmask",
- (PyCFunction)xu_notifier_unmask,
- METH_VARARGS,
- "Unmask notifications for a @port.\n" },
-
- { "bind",
- (PyCFunction)xu_notifier_bind,
- METH_VARARGS,
- "Get notifications for a @port.\n" },
-
- { "unbind",
- (PyCFunction)xu_notifier_unbind,
- METH_VARARGS,
- "No longer get notifications for a @port.\n" },
-
- { "fileno",
- (PyCFunction)xu_notifier_fileno,
- METH_VARARGS,
- "Return the file descriptor for the notification channel.\n" },
-
- { NULL, NULL, 0, NULL }
-};
-
-staticforward PyTypeObject xu_notifier_type;
-
-static PyObject *xu_notifier_new(PyObject *self, PyObject *args)
-{
- xu_notifier_object *xun;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- xun = PyObject_New(xu_notifier_object, &xu_notifier_type);
-
- reopen:
- xun->evtchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR);
- if ( xun->evtchn_fd == -1 )
- {
- if ( (errno == ENOENT) &&
- ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
- (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600,
- (EVTCHN_DEV_MAJOR << 8) | EVTCHN_DEV_MINOR) == 0) )
- goto reopen;
- PyObject_Del((PyObject *)xun);
- return PyErr_SetFromErrno(PyExc_IOError);
- }
-
- return (PyObject *)xun;
-}
-
-static PyObject *xu_notifier_getattr(PyObject *obj, char *name)
-{
- if ( strcmp(name, "EXCEPTION") == 0 )
- return PyInt_FromLong(PORT_EXCEPTION);
- if ( strcmp(name, "NORMAL") == 0 )
- return PyInt_FromLong(PORT_NORMAL);
- return Py_FindMethod(xu_notifier_methods, obj, name);
-}
-
-static void xu_notifier_dealloc(PyObject *self)
-{
- xu_notifier_object *xun = (xu_notifier_object *)self;
- (void)close(xun->evtchn_fd);
- PyObject_Del(self);
-}
-
-static PyTypeObject xu_notifier_type = {
- PyObject_HEAD_INIT(&PyType_Type)
- 0,
- "notifier",
- sizeof(xu_notifier_object),
- 0,
- xu_notifier_dealloc, /* tp_dealloc */
- NULL, /* tp_print */
- xu_notifier_getattr, /* tp_getattr */
- NULL, /* tp_setattr */
- NULL, /* tp_compare */
- NULL, /* tp_repr */
- NULL, /* tp_as_number */
- NULL, /* tp_as_sequence */
- NULL, /* tp_as_mapping */
- NULL /* tp_hash */
-};
-
-
-
-/*
- * *********************** MESSAGE ***********************
- */
-
-#define TYPE(_x,_y) (((_x)<<8)|(_y))
-#define P2C(_struct, _field, _ctype) \
- do { \
- PyObject *obj; \
- if ( (obj = PyDict_GetItemString(payload, #_field)) != NULL ) \
- { \
- if ( PyInt_Check(obj) ) \
- { \
- ((_struct *)&xum->msg.msg[0])->_field = \
- (_ctype)PyInt_AsLong(obj); \
- dict_items_parsed++; \
- } \
- else if ( PyLong_Check(obj) ) \
- { \
- ((_struct *)&xum->msg.msg[0])->_field = \
- (_ctype)PyLong_AsUnsignedLongLong(obj); \
- dict_items_parsed++; \
- } \
- } \
- xum->msg.length = sizeof(_struct); \
- } while ( 0 )
-#define C2P(_struct, _field, _pytype, _ctype) \
- do { \
- PyObject *obj = Py ## _pytype ## _From ## _ctype \
- (((_struct *)&xum->msg.msg[0])->_field); \
- if ( dict == NULL ) dict = PyDict_New(); \
- PyDict_SetItemString(dict, #_field, obj); \
- } while ( 0 )
-
-typedef struct {
- PyObject_HEAD;
- control_msg_t msg;
-} xu_message_object;
-
-static PyObject *xu_message_append_payload(PyObject *self, PyObject *args)
-{
- xu_message_object *xum = (xu_message_object *)self;
- char *str;
- int len;
-
- if ( !PyArg_ParseTuple(args, "s#", &str, &len) )
- return NULL;
-
- if ( (len + xum->msg.length) > sizeof(xum->msg.msg) )
- {
- PyErr_SetString(PyExc_RuntimeError, "out of space in control message");
- return NULL;
- }
-
- memcpy(&xum->msg.msg[xum->msg.length], str, len);
- xum->msg.length += len;
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *xu_message_set_response_fields(PyObject *self, PyObject *args)
-{
- xu_message_object *xum = (xu_message_object *)self;
- PyObject *payload;
- int dict_items_parsed = 0;
-
- if ( !PyArg_ParseTuple(args, "O", &payload) )
- return NULL;
-
- if ( !PyDict_Check(payload) )
- {
- PyErr_SetString(PyExc_TypeError, "payload is not a dictionary");
- return NULL;
- }
-
- switch ( TYPE(xum->msg.type, xum->msg.subtype) )
- {
- case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED):
- P2C(blkif_fe_driver_status_changed_t, nr_interfaces, u32);
- break;
- case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED):
- P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32);
- break;
- }
-
- if ( dict_items_parsed != PyDict_Size(payload) )
- {
- PyErr_SetString(PyExc_TypeError, "payload contains bad items");
- return NULL;
- }
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *xu_message_get_payload(PyObject *self, PyObject *args)
-{
- xu_message_object *xum = (xu_message_object *)self;
- PyObject *dict = NULL;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- switch ( TYPE(xum->msg.type, xum->msg.subtype) )
- {
- case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED):
- C2P(blkif_fe_interface_status_changed_t, handle, Int, Long);
- C2P(blkif_fe_interface_status_changed_t, status, Int, Long);
- C2P(blkif_fe_interface_status_changed_t, evtchn, Int, Long);
- return dict;
- case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED):
- C2P(blkif_fe_driver_status_changed_t, status, Int, Long);
- return dict;
- case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT):
- C2P(blkif_fe_interface_connect_t, handle, Int, Long);
- C2P(blkif_fe_interface_connect_t, shmem_frame, Int, Long);
- return dict;
- case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_DISCONNECT):
- C2P(blkif_fe_interface_disconnect_t, handle, Int, Long);
- return dict;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE):
- C2P(blkif_be_create_t, domid, Int, Long);
- C2P(blkif_be_create_t, blkif_handle, Int, Long);
- C2P(blkif_be_create_t, status, Int, Long);
- return dict;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY):
- C2P(blkif_be_destroy_t, domid, Int, Long);
- C2P(blkif_be_destroy_t, blkif_handle, Int, Long);
- C2P(blkif_be_destroy_t, status, Int, Long);
- return dict;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT):
- C2P(blkif_be_connect_t, domid, Int, Long);
- C2P(blkif_be_connect_t, blkif_handle, Int, Long);
- C2P(blkif_be_connect_t, shmem_frame, Int, Long);
- C2P(blkif_be_connect_t, evtchn, Int, Long);
- C2P(blkif_be_connect_t, status, Int, Long);
- return dict;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT):
- C2P(blkif_be_disconnect_t, domid, Int, Long);
- C2P(blkif_be_disconnect_t, blkif_handle, Int, Long);
- C2P(blkif_be_disconnect_t, status, Int, Long);
- return dict;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE):
- C2P(blkif_be_vbd_create_t, domid, Int, Long);
- C2P(blkif_be_vbd_create_t, blkif_handle, Int, Long);
- C2P(blkif_be_vbd_create_t, vdevice, Int, Long);
- C2P(blkif_be_vbd_create_t, readonly, Int, Long);
- C2P(blkif_be_vbd_create_t, status, Int, Long);
- return dict;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY):
- C2P(blkif_be_vbd_destroy_t, domid, Int, Long);
- C2P(blkif_be_vbd_destroy_t, blkif_handle, Int, Long);
- C2P(blkif_be_vbd_destroy_t, vdevice, Int, Long);
- C2P(blkif_be_vbd_destroy_t, status, Int, Long);
- return dict;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW):
- C2P(blkif_be_vbd_grow_t, domid, Int, Long);
- C2P(blkif_be_vbd_grow_t, blkif_handle, Int, Long);
- C2P(blkif_be_vbd_grow_t, vdevice, Int, Long);
- C2P(blkif_be_vbd_grow_t, extent.sector_start,
- Long, UnsignedLongLong);
- C2P(blkif_be_vbd_grow_t, extent.sector_length,
- Long, UnsignedLongLong);
- C2P(blkif_be_vbd_grow_t, extent.device, Int, Long);
- C2P(blkif_be_vbd_grow_t, status, Int, Long);
- return dict;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_SHRINK):
- C2P(blkif_be_vbd_shrink_t, domid, Int, Long);
- C2P(blkif_be_vbd_shrink_t, blkif_handle, Int, Long);
- C2P(blkif_be_vbd_shrink_t, vdevice, Int, Long);
- C2P(blkif_be_vbd_shrink_t, status, Int, Long);
- return dict;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED):
- C2P(blkif_be_driver_status_changed_t, status, Int, Long);
- return dict;
- case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED):
- C2P(netif_fe_interface_status_changed_t, handle, Int, Long);
- C2P(netif_fe_interface_status_changed_t, status, Int, Long);
- C2P(netif_fe_interface_status_changed_t, evtchn, Int, Long);
- return dict;
- case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED):
- C2P(netif_fe_driver_status_changed_t, status, Int, Long);
- C2P(netif_fe_driver_status_changed_t, nr_interfaces, Int, Long);
- return dict;
- case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT):
- C2P(netif_fe_interface_connect_t, handle, Int, Long);
- C2P(netif_fe_interface_connect_t, tx_shmem_frame, Int, Long);
- C2P(netif_fe_interface_connect_t, rx_shmem_frame, Int, Long);
- return dict;
- case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_DISCONNECT):
- C2P(netif_fe_interface_disconnect_t, handle, Int, Long);
- return dict;
- case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE):
- C2P(netif_be_create_t, domid, Int, Long);
- C2P(netif_be_create_t, netif_handle, Int, Long);
- C2P(netif_be_create_t, status, Int, Long);
- return dict;
- case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY):
- C2P(netif_be_destroy_t, domid, Int, Long);
- C2P(netif_be_destroy_t, netif_handle, Int, Long);
- C2P(netif_be_destroy_t, status, Int, Long);
- return dict;
- case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT):
- C2P(netif_be_connect_t, domid, Int, Long);
- C2P(netif_be_connect_t, netif_handle, Int, Long);
- C2P(netif_be_connect_t, tx_shmem_frame, Int, Long);
- C2P(netif_be_connect_t, rx_shmem_frame, Int, Long);
- C2P(netif_be_connect_t, evtchn, Int, Long);
- C2P(netif_be_connect_t, status, Int, Long);
- return dict;
- case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT):
- C2P(netif_be_disconnect_t, domid, Int, Long);
- C2P(netif_be_disconnect_t, netif_handle, Int, Long);
- C2P(netif_be_disconnect_t, status, Int, Long);
- return dict;
- case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED):
- C2P(netif_be_driver_status_changed_t, status, Int, Long);
- return dict;
- }
-
- return PyString_FromStringAndSize(xum->msg.msg, xum->msg.length);
-}
-
-static PyObject *xu_message_get_header(PyObject *self, PyObject *args)
-{
- xu_message_object *xum = (xu_message_object *)self;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- return Py_BuildValue("{s:i,s:i,s:i}",
- "type", xum->msg.type,
- "subtype", xum->msg.subtype,
- "id", xum->msg.id);
-}
-
-static PyMethodDef xu_message_methods[] = {
- { "append_payload",
- (PyCFunction)xu_message_append_payload,
- METH_VARARGS,
- "Append @str to the message payload.\n" },
-
- { "set_response_fields",
- (PyCFunction)xu_message_set_response_fields,
- METH_VARARGS,
- "Fill in the response fields in a message that was passed to us.\n" },
-
- { "get_payload",
- (PyCFunction)xu_message_get_payload,
- METH_VARARGS,
- "Return the message payload in string form.\n" },
-
- { "get_header",
- (PyCFunction)xu_message_get_header,
- METH_VARARGS,
- "Returns a dictionary of values for @type, @subtype, and @id.\n" },
-
- { NULL, NULL, 0, NULL }
-};
-
-staticforward PyTypeObject xu_message_type;
-
-static PyObject *xu_message_new(PyObject *self, PyObject *args)
-{
- xu_message_object *xum;
- int type, subtype, id, dict_items_parsed = 0;
- PyObject *payload = NULL;
-
- if ( !PyArg_ParseTuple(args, "iii|O", &type, &subtype, &id, &payload) )
- return NULL;
-
- xum = PyObject_New(xu_message_object, &xu_message_type);
-
- xum->msg.type = type;
- xum->msg.subtype = subtype;
- xum->msg.id = id;
- xum->msg.length = 0;
-
- if ( payload == NULL )
- return (PyObject *)xum;
-
- if ( !PyDict_Check(payload) )
- {
- PyErr_SetString(PyExc_TypeError, "payload is not a dictionary");
- PyObject_Del((PyObject *)xum);
- return NULL;
- }
-
- switch ( TYPE(type, subtype) )
- {
- case TYPE(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED):
- P2C(blkif_fe_interface_status_changed_t, handle, u32);
- P2C(blkif_fe_interface_status_changed_t, status, u32);
- P2C(blkif_fe_interface_status_changed_t, evtchn, u16);
- break;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE):
- P2C(blkif_be_create_t, domid, u32);
- P2C(blkif_be_create_t, blkif_handle, u32);
- break;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY):
- P2C(blkif_be_destroy_t, domid, u32);
- P2C(blkif_be_destroy_t, blkif_handle, u32);
- break;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT):
- P2C(blkif_be_connect_t, domid, u32);
- P2C(blkif_be_connect_t, blkif_handle, u32);
- P2C(blkif_be_connect_t, shmem_frame, memory_t);
- P2C(blkif_be_connect_t, evtchn, u16);
- break;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT):
- P2C(blkif_be_disconnect_t, domid, u32);
- P2C(blkif_be_disconnect_t, blkif_handle, u32);
- break;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE):
- P2C(blkif_be_vbd_create_t, domid, u32);
- P2C(blkif_be_vbd_create_t, blkif_handle, u32);
- P2C(blkif_be_vbd_create_t, vdevice, blkif_vdev_t);
- P2C(blkif_be_vbd_create_t, readonly, u16);
- break;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY):
- P2C(blkif_be_vbd_destroy_t, domid, u32);
- P2C(blkif_be_vbd_destroy_t, blkif_handle, u32);
- P2C(blkif_be_vbd_destroy_t, vdevice, blkif_vdev_t);
- break;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW):
- P2C(blkif_be_vbd_grow_t, domid, u32);
- P2C(blkif_be_vbd_grow_t, blkif_handle, u32);
- P2C(blkif_be_vbd_grow_t, vdevice, blkif_vdev_t);
- P2C(blkif_be_vbd_grow_t, extent.sector_start, blkif_sector_t);
- P2C(blkif_be_vbd_grow_t, extent.sector_length, blkif_sector_t);
- P2C(blkif_be_vbd_grow_t, extent.device, blkif_pdev_t);
- break;
- case TYPE(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_SHRINK):
- P2C(blkif_be_vbd_shrink_t, domid, u32);
- P2C(blkif_be_vbd_shrink_t, blkif_handle, u32);
- P2C(blkif_be_vbd_shrink_t, vdevice, blkif_vdev_t);
- break;
- case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED):
- P2C(netif_fe_interface_status_changed_t, handle, u32);
- P2C(netif_fe_interface_status_changed_t, status, u32);
- P2C(netif_fe_interface_status_changed_t, evtchn, u16);
- P2C(netif_fe_interface_status_changed_t, mac[0], u8);
- P2C(netif_fe_interface_status_changed_t, mac[1], u8);
- P2C(netif_fe_interface_status_changed_t, mac[2], u8);
- P2C(netif_fe_interface_status_changed_t, mac[3], u8);
- P2C(netif_fe_interface_status_changed_t, mac[4], u8);
- P2C(netif_fe_interface_status_changed_t, mac[5], u8);
- break;
- case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE):
- P2C(netif_be_create_t, domid, u32);
- P2C(netif_be_create_t, netif_handle, u32);
- P2C(netif_be_create_t, mac[0], u8);
- P2C(netif_be_create_t, mac[1], u8);
- P2C(netif_be_create_t, mac[2], u8);
- P2C(netif_be_create_t, mac[3], u8);
- P2C(netif_be_create_t, mac[4], u8);
- P2C(netif_be_create_t, mac[5], u8);
- break;
- case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY):
- P2C(netif_be_destroy_t, domid, u32);
- P2C(netif_be_destroy_t, netif_handle, u32);
- break;
- case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT):
- P2C(netif_be_connect_t, domid, u32);
- P2C(netif_be_connect_t, netif_handle, u32);
- P2C(netif_be_connect_t, tx_shmem_frame, memory_t);
- P2C(netif_be_connect_t, rx_shmem_frame, memory_t);
- P2C(netif_be_connect_t, evtchn, u16);
- break;
- case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT):
- P2C(netif_be_disconnect_t, domid, u32);
- P2C(netif_be_disconnect_t, netif_handle, u32);
- break;
- case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED):
- P2C(netif_fe_driver_status_changed_t, status, u32);
- P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32);
- break;
- }
-
- if ( dict_items_parsed != PyDict_Size(payload) )
- {
- PyErr_SetString(PyExc_TypeError, "payload contains bad items");
- PyObject_Del((PyObject *)xum);
- return NULL;
- }
-
- return (PyObject *)xum;
-}
-
-static PyObject *xu_message_getattr(PyObject *obj, char *name)
-{
- xu_message_object *xum;
- if ( strcmp(name, "MAX_PAYLOAD") == 0 )
- return PyInt_FromLong(sizeof(xum->msg.msg));
- return Py_FindMethod(xu_message_methods, obj, name);
-}
-
-static void xu_message_dealloc(PyObject *self)
-{
- PyObject_Del(self);
-}
-
-static PyTypeObject xu_message_type = {
- PyObject_HEAD_INIT(&PyType_Type)
- 0,
- "message",
- sizeof(xu_message_object),
- 0,
- xu_message_dealloc, /* tp_dealloc */
- NULL, /* tp_print */
- xu_message_getattr, /* tp_getattr */
- NULL, /* tp_setattr */
- NULL, /* tp_compare */
- NULL, /* tp_repr */
- NULL, /* tp_as_number */
- NULL, /* tp_as_sequence */
- NULL, /* tp_as_mapping */
- NULL /* tp_hash */
-};
-
-
-
-/*
- * *********************** PORT ***********************
- */
-
-static control_if_t *map_control_interface(int fd, unsigned long pfn)
-{
- char *vaddr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE,
- MAP_SHARED, fd, pfn * PAGE_SIZE);
- if ( vaddr == MAP_FAILED )
- return NULL;
- return (control_if_t *)(vaddr + 2048);
-}
-static void unmap_control_interface(int fd, control_if_t *c)
-{
- char *vaddr = (char *)c - 2048;
- (void)munmap(vaddr, PAGE_SIZE);
-}
-
-typedef struct xu_port_object {
- PyObject_HEAD;
- int mem_fd;
- int xc_handle;
- u32 remote_dom;
- int local_port, remote_port;
- control_if_t *interface;
- CONTROL_RING_IDX tx_req_cons, tx_resp_prod;
- CONTROL_RING_IDX rx_req_prod, rx_resp_cons;
-} xu_port_object;
-
-static PyObject *port_error;
-
-static int xup_connect(xu_port_object *xup, domid_t dom,
- int local_port, int remote_port){
- // From our prespective rx = producer, tx = consumer.
- int err = 0;
- printf("%s> dom=%u %d:%d\n", __FUNCTION__, (unsigned int)dom,
- local_port, remote_port);
-
- // Consumer = tx.
- //xup->interface->tx_resp_prod = 0;
- //xup->interface->tx_req_prod = 0;
- xup->tx_resp_prod = xup->interface->tx_resp_prod;
- xup->tx_req_cons = xup->interface->tx_resp_prod;
- printf("%s> tx: %u %u : %u %u\n", __FUNCTION__,
- (unsigned int)xup->interface->tx_resp_prod,
- (unsigned int)xup->tx_resp_prod,
- (unsigned int)xup->tx_req_cons,
- (unsigned int)xup->interface->tx_req_prod);
-
- // Producer = rx.
- //xup->interface->rx_req_prod = 0;
- //xup->interface->rx_resp_prod = 0;
- xup->rx_req_prod = xup->interface->rx_req_prod;
- xup->rx_resp_cons = xup->interface->rx_resp_prod;
- printf("%s> rx: %u %u : %u %u\n", __FUNCTION__,
- (unsigned int)xup->rx_resp_cons,
- (unsigned int)xup->interface->rx_resp_prod,
- (unsigned int)xup->interface->rx_req_prod,
- (unsigned int)xup->rx_req_prod);
-
- xup->remote_dom = dom;
- xup->local_port = local_port;
- xup->remote_port = remote_port;
-
- printf("%s< err=%d\n", __FUNCTION__, err);
- return err;
-}
-
-static PyObject *xu_port_notify(PyObject *self, PyObject *args)
-{
- xu_port_object *xup = (xu_port_object *)self;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- (void)xc_evtchn_send(xup->xc_handle, xup->local_port);
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *xu_port_read_request(PyObject *self, PyObject *args)
-{
- xu_port_object *xup = (xu_port_object *)self;
- xu_message_object *xum;
- CONTROL_RING_IDX c = xup->tx_req_cons;
- control_if_t *cif = xup->interface;
- control_msg_t *cmsg;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- if ( (c == cif->tx_req_prod) ||
- ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) )
- {
- PyErr_SetString(port_error, "no request to read");
- return NULL;
- }
-
- cmsg = &cif->tx_ring[MASK_CONTROL_IDX(c)];
- xum = PyObject_New(xu_message_object, &xu_message_type);
- memcpy(&xum->msg, cmsg, sizeof(*cmsg));
- if ( xum->msg.length > sizeof(xum->msg.msg) )
- xum->msg.length = sizeof(xum->msg.msg);
- xup->tx_req_cons++;
- return (PyObject *)xum;
-}
-
-static PyObject *xu_port_write_request(PyObject *self, PyObject *args)
-{
- xu_port_object *xup = (xu_port_object *)self;
- xu_message_object *xum;
- CONTROL_RING_IDX p = xup->rx_req_prod;
- control_if_t *cif = xup->interface;
- control_msg_t *cmsg;
-
- if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) )
- return NULL;
-
- if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) )
- {
- PyErr_SetString(PyExc_TypeError, "expected a " XENPKG ".message");
- return NULL;
- }
-
- if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) )
- {
- PyErr_SetString(port_error, "no space to write request");
- return NULL;
- }
-
- cmsg = &cif->rx_ring[MASK_CONTROL_IDX(p)];
- memcpy(cmsg, &xum->msg, sizeof(*cmsg));
-
- xup->rx_req_prod = cif->rx_req_prod = p + 1;
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *xu_port_read_response(PyObject *self, PyObject *args)
-{
- xu_port_object *xup = (xu_port_object *)self;
- xu_message_object *xum;
- CONTROL_RING_IDX c = xup->rx_resp_cons;
- control_if_t *cif = xup->interface;
- control_msg_t *cmsg;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) )
- {
- PyErr_SetString(port_error, "no response to read");
- return NULL;
- }
-
- cmsg = &cif->rx_ring[MASK_CONTROL_IDX(c)];
- xum = PyObject_New(xu_message_object, &xu_message_type);
- memcpy(&xum->msg, cmsg, sizeof(*cmsg));
- if ( xum->msg.length > sizeof(xum->msg.msg) )
- xum->msg.length = sizeof(xum->msg.msg);
- xup->rx_resp_cons++;
- return (PyObject *)xum;
-}
-
-static PyObject *xu_port_write_response(PyObject *self, PyObject *args)
-{
- xu_port_object *xup = (xu_port_object *)self;
- xu_message_object *xum;
- CONTROL_RING_IDX p = xup->tx_resp_prod;
- control_if_t *cif = xup->interface;
- control_msg_t *cmsg;
-
- if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) )
- return NULL;
-
- if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) )
- {
- PyErr_SetString(PyExc_TypeError, "expected a " XENPKG ".message");
- return NULL;
- }
-
- if ( p == xup->tx_req_cons )
- {
- PyErr_SetString(port_error, "no space to write response");
- return NULL;
- }
-
- cmsg = &cif->tx_ring[MASK_CONTROL_IDX(p)];
- memcpy(cmsg, &xum->msg, sizeof(*cmsg));
-
- xup->tx_resp_prod = cif->tx_resp_prod = p + 1;
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *xu_port_request_to_read(PyObject *self, PyObject *args)
-{
- xu_port_object *xup = (xu_port_object *)self;
- CONTROL_RING_IDX c = xup->tx_req_cons;
- control_if_t *cif = xup->interface;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- if ( (c == cif->tx_req_prod) ||
- ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) )
- return PyInt_FromLong(0);
-
- return PyInt_FromLong(1);
-}
-
-static PyObject *xu_port_space_to_write_request(PyObject *self, PyObject *args)
-{
- xu_port_object *xup = (xu_port_object *)self;
- CONTROL_RING_IDX p = xup->rx_req_prod;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) )
- return PyInt_FromLong(0);
-
- return PyInt_FromLong(1);
-}
-
-static PyObject *xu_port_response_to_read(PyObject *self, PyObject *args)
-{
- xu_port_object *xup = (xu_port_object *)self;
- CONTROL_RING_IDX c = xup->rx_resp_cons;
- control_if_t *cif = xup->interface;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) )
- return PyInt_FromLong(0);
-
- return PyInt_FromLong(1);
-}
-
-static PyObject *xu_port_space_to_write_response(
- PyObject *self, PyObject *args)
-{
- xu_port_object *xup = (xu_port_object *)self;
- CONTROL_RING_IDX p = xup->tx_resp_prod;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- if ( p == xup->tx_req_cons )
- return PyInt_FromLong(0);
-
- return PyInt_FromLong(1);
-}
-
-static PyMethodDef xu_port_methods[] = {
- { "notify",
- (PyCFunction)xu_port_notify,
- METH_VARARGS,
- "Send a notification to the remote end.\n" },
-
- { "read_request",
- (PyCFunction)xu_port_read_request,
- METH_VARARGS,
- "Read a request message from the control interface.\n" },
-
- { "write_request",
- (PyCFunction)xu_port_write_request,
- METH_VARARGS,
- "Write a request message to the control interface.\n" },
-
- { "read_response",
- (PyCFunction)xu_port_read_response,
- METH_VARARGS,
- "Read a response message from the control interface.\n" },
-
- { "write_response",
- (PyCFunction)xu_port_write_response,
- METH_VARARGS,
- "Write a response message to the control interface.\n" },
-
- { "request_to_read",
- (PyCFunction)xu_port_request_to_read,
- METH_VARARGS,
- "Returns TRUE if there is a request message to read.\n" },
-
- { "space_to_write_request",
- (PyCFunction)xu_port_space_to_write_request,
- METH_VARARGS,
- "Returns TRUE if there is space to write a request message.\n" },
-
- { "response_to_read",
- (PyCFunction)xu_port_response_to_read,
- METH_VARARGS,
- "Returns TRUE if there is a response message to read.\n" },
-
- { "space_to_write_response",
- (PyCFunction)xu_port_space_to_write_response,
- METH_VARARGS,
- "Returns TRUE if there is space to write a response message.\n" },
-
- { NULL, NULL, 0, NULL }
-};
-
-staticforward PyTypeObject xu_port_type;
-
-static PyObject *xu_port_new(PyObject *self, PyObject *args)
-{
- xu_port_object *xup;
- u32 dom;
- int port1, port2;
- xc_dominfo_t info;
-
- if ( !PyArg_ParseTuple(args, "i", &dom) )
- return NULL;
-
- xup = PyObject_New(xu_port_object, &xu_port_type);
-
- if ( (xup->mem_fd = open("/dev/mem", O_RDWR)) == -1 )
- {
- PyErr_SetString(port_error, "Could not open '/dev/mem'");
- goto fail1;
- }
-
- /* Set the General-Purpose Subject whose page frame will be mapped. */
- (void)ioctl(xup->mem_fd, _IO('M', 1), (unsigned long)dom);
-
- if ( (xup->xc_handle = xc_interface_open()) == -1 )
- {
- PyErr_SetString(port_error, "Could not open Xen control interface");
- goto fail2;
- }
-
- if ( dom == 0 )
- {
- /*
- * The control-interface event channel for DOM0 is already set up.
- * We use an ioctl to discover the port at our end of the channel.
- */
- port1 = ioctl(xup->xc_handle, IOCTL_PRIVCMD_INITDOMAIN_EVTCHN, NULL);
- port2 = -1; /* We don't need the remote end of the DOM0 link. */
- if ( port1 < 0 )
- {
- PyErr_SetString(port_error, "Could not open channel to DOM0");
- goto fail3;
- }
- }
- else if ( xc_evtchn_bind_interdomain(xup->xc_handle,
- DOMID_SELF, dom,
- &port1, &port2) != 0 )
- {
- PyErr_SetString(port_error, "Could not open channel to domain");
- goto fail3;
- }
-
- if ( (xc_domain_getinfo(xup->xc_handle, dom, 1, &info) != 1) ||
- (info.domid != dom) )
- {
- PyErr_SetString(port_error, "Failed to obtain domain status");
- goto fail4;
- }
-
- xup->interface =
- map_control_interface(xup->mem_fd, info.shared_info_frame);
- if ( xup->interface == NULL )
- {
- PyErr_SetString(port_error, "Failed to map domain control interface");
- goto fail4;
- }
-
- xup_connect(xup, dom, port1, port2);
- return (PyObject *)xup;
-
-
- fail4:
- (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, port1);
- fail3:
- (void)xc_interface_close(xup->xc_handle);
- fail2:
- (void)close(xup->mem_fd);
- fail1:
- PyObject_Del((PyObject *)xup);
- return NULL;
-}
-
-static PyObject *xu_port_getattr(PyObject *obj, char *name)
-{
- xu_port_object *xup = (xu_port_object *)obj;
- if ( strcmp(name, "local_port") == 0 )
- return PyInt_FromLong(xup->local_port);
- if ( strcmp(name, "remote_port") == 0 )
- return PyInt_FromLong(xup->remote_port);
- if ( strcmp(name, "remote_dom") == 0 )
- return PyInt_FromLong(xup->remote_dom);
- return Py_FindMethod(xu_port_methods, obj, name);
-}
-
-static void xu_port_dealloc(PyObject *self)
-{
- xu_port_object *xup = (xu_port_object *)self;
- unmap_control_interface(xup->mem_fd, xup->interface);
- if ( xup->remote_dom != 0 )
- (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, xup->local_port);
- (void)xc_interface_close(xup->xc_handle);
- (void)close(xup->mem_fd);
- PyObject_Del(self);
-}
-
-static PyTypeObject xu_port_type = {
- PyObject_HEAD_INIT(&PyType_Type)
- 0,
- "port",
- sizeof(xu_port_object),
- 0,
- xu_port_dealloc, /* tp_dealloc */
- NULL, /* tp_print */
- xu_port_getattr, /* tp_getattr */
- NULL, /* tp_setattr */
- NULL, /* tp_compare */
- NULL, /* tp_repr */
- NULL, /* tp_as_number */
- NULL, /* tp_as_sequence */
- NULL, /* tp_as_mapping */
- NULL /* tp_hash */
-};
-
-
-
-/*
- * *********************** BUFFER ***********************
- */
-
-#define BUFSZ 65536
-#define MASK_BUF_IDX(_i) ((_i)&(BUFSZ-1))
-typedef unsigned int BUF_IDX;
-
-typedef struct {
- PyObject_HEAD;
- char *buf;
- unsigned int prod, cons;
-} xu_buffer_object;
-
-static PyObject *__xu_buffer_peek(xu_buffer_object *xub, int max)
-{
- PyObject *str1, *str2;
- int len1, len2, c = MASK_BUF_IDX(xub->cons);
-
- len1 = xub->prod - xub->cons;
- if ( len1 > (BUFSZ - c) ) /* clip to ring wrap */
- len1 = BUFSZ - c;
- if ( len1 > max ) /* clip to specified maximum */
- len1 = max;
- if ( len1 < 0 ) /* sanity */
- len1 = 0;
-
- if ( (str1 = PyString_FromStringAndSize(&xub->buf[c], len1)) == NULL )
- return NULL;
-
- if ( (len1 < (xub->prod - xub->cons)) && (len1 < max) )
- {
- len2 = max - len1;
- if ( len2 > MASK_BUF_IDX(xub->prod) )
- len2 = MASK_BUF_IDX(xub->prod);
- if ( len2 > 0 )
- {
- str2 = PyString_FromStringAndSize(&xub->buf[0], len2);
- if ( str2 == NULL )
- return NULL;
- PyString_ConcatAndDel(&str1, str2);
- if ( str1 == NULL )
- return NULL;
- }
- }
-
- return str1;
-}
-
-static PyObject *xu_buffer_peek(PyObject *self, PyObject *args)
-{
- xu_buffer_object *xub = (xu_buffer_object *)self;
- int max = 1024;
-
- if ( !PyArg_ParseTuple(args, "|i", &max) )
- return NULL;
-
- return __xu_buffer_peek(xub, max);
-}
-
-static PyObject *xu_buffer_read(PyObject *self, PyObject *args)
-{
- xu_buffer_object *xub = (xu_buffer_object *)self;
- PyObject *str;
- int max = 1024;
-
- if ( !PyArg_ParseTuple(args, "|i", &max) )
- return NULL;
-
- if ( (str = __xu_buffer_peek(xub, max)) != NULL )
- xub->cons += PyString_Size(str);
-
- return str;
-}
-
-static PyObject *xu_buffer_discard(PyObject *self, PyObject *args)
-{
- xu_buffer_object *xub = (xu_buffer_object *)self;
- int max, len;
-
- if ( !PyArg_ParseTuple(args, "i", &max) )
- return NULL;
-
- len = xub->prod - xub->cons;
- if ( len > max )
- len = max;
- if ( len < 0 )
- len = 0;
-
- xub->cons += len;
-
- return PyInt_FromLong(len);
-}
-
-static PyObject *xu_buffer_write(PyObject *self, PyObject *args)
-{
- xu_buffer_object *xub = (xu_buffer_object *)self;
- char *str;
- int len, len1, len2;
-
- if ( !PyArg_ParseTuple(args, "s#", &str, &len) )
- return NULL;
-
- len1 = len;
- if ( len1 > (BUFSZ - MASK_BUF_IDX(xub->prod)) )
- len1 = BUFSZ - MASK_BUF_IDX(xub->prod);
- if ( len1 > (BUFSZ - (xub->prod - xub->cons)) )
- len1 = BUFSZ - (xub->prod - xub->cons);
-
- if ( len1 == 0 )
- return PyInt_FromLong(0);
-
- memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[0], len1);
- xub->prod += len1;
-
- if ( len1 < len )
- {
- len2 = len - len1;
- if ( len2 > (BUFSZ - MASK_BUF_IDX(xub->prod)) )
- len2 = BUFSZ - MASK_BUF_IDX(xub->prod);
- if ( len2 > (BUFSZ - (xub->prod - xub->cons)) )
- len2 = BUFSZ - (xub->prod - xub->cons);
- if ( len2 != 0 )
- {
- memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[len1], len2);
- xub->prod += len2;
- return PyInt_FromLong(len1 + len2);
- }
- }
-
- return PyInt_FromLong(len1);
-}
-
-static PyObject *xu_buffer_empty(PyObject *self, PyObject *args)
-{
- xu_buffer_object *xub = (xu_buffer_object *)self;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- if ( xub->cons == xub->prod )
- return PyInt_FromLong(1);
-
- return PyInt_FromLong(0);
-}
-
-static PyObject *xu_buffer_full(PyObject *self, PyObject *args)
-{
- xu_buffer_object *xub = (xu_buffer_object *)self;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- if ( (xub->prod - xub->cons) == BUFSZ )
- return PyInt_FromLong(1);
-
- return PyInt_FromLong(0);
-}
-
-static PyMethodDef xu_buffer_methods[] = {
- { "peek",
- (PyCFunction)xu_buffer_peek,
- METH_VARARGS,
- "Peek up to @max bytes from the buffer. Returns a string.\n" },
-
- { "read",
- (PyCFunction)xu_buffer_read,
- METH_VARARGS,
- "Read up to @max bytes from the buffer. Returns a string.\n" },
-
- { "discard",
- (PyCFunction)xu_buffer_discard,
- METH_VARARGS,
- "Discard up to @max bytes from the buffer. Returns number of bytes.\n" },
-
- { "write",
- (PyCFunction)xu_buffer_write,
- METH_VARARGS,
- "Write @string into buffer. Return number of bytes written.\n" },
-
- { "empty",
- (PyCFunction)xu_buffer_empty,
- METH_VARARGS,
- "Return TRUE if the buffer is empty.\n" },
-
- { "full",
- (PyCFunction)xu_buffer_full,
- METH_VARARGS,
- "Return TRUE if the buffer is full.\n" },
-
- { NULL, NULL, 0, NULL }
-};
-
-staticforward PyTypeObject xu_buffer_type;
-
-static PyObject *xu_buffer_new(PyObject *self, PyObject *args)
-{
- xu_buffer_object *xub;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- xub = PyObject_New(xu_buffer_object, &xu_buffer_type);
-
- if ( (xub->buf = malloc(BUFSZ)) == NULL )
- {
- PyObject_Del((PyObject *)xub);
- return NULL;
- }
-
- xub->prod = xub->cons = 0;
-
- return (PyObject *)xub;
-}
-
-static PyObject *xu_buffer_getattr(PyObject *obj, char *name)
-{
- return Py_FindMethod(xu_buffer_methods, obj, name);
-}
-
-static void xu_buffer_dealloc(PyObject *self)
-{
- xu_buffer_object *xub = (xu_buffer_object *)self;
- free(xub->buf);
- PyObject_Del(self);
-}
-
-static PyTypeObject xu_buffer_type = {
- PyObject_HEAD_INIT(&PyType_Type)
- 0,
- "buffer",
- sizeof(xu_buffer_object),
- 0,
- xu_buffer_dealloc, /* tp_dealloc */
- NULL, /* tp_print */
- xu_buffer_getattr, /* tp_getattr */
- NULL, /* tp_setattr */
- NULL, /* tp_compare */
- NULL, /* tp_repr */
- NULL, /* tp_as_number */
- NULL, /* tp_as_sequence */
- NULL, /* tp_as_mapping */
- NULL /* tp_hash */
-};
-
-
-
-/*
- * *********************** MODULE WRAPPER ***********************
- */
-
-static void handle_child_death(int dummy)
-{
- while ( waitpid(-1, NULL, WNOHANG) > 0 )
- continue;
-}
-
-static PyObject *xu_autoreap(PyObject *self, PyObject *args)
-{
- struct sigaction sa;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = handle_child_death;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
- (void)sigaction(SIGCHLD, &sa, NULL);
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyMethodDef xu_methods[] = {
- { "notifier", xu_notifier_new, METH_VARARGS,
- "Create a new notifier." },
- { "message", xu_message_new, METH_VARARGS,
- "Create a new communications message." },
- { "port", xu_port_new, METH_VARARGS,
- "Create a new communications port." },
- { "buffer", xu_buffer_new, METH_VARARGS,
- "Create a new ring buffer." },
- { "autoreap", xu_autoreap, METH_VARARGS,
- "Ensure that zombie children are automatically reaped by the OS." },
- { NULL, NULL, 0, NULL }
-};
-
-PyMODINIT_FUNC initxu(void)
-{
- PyObject *m, *d;
-
- m = Py_InitModule(XENPKG, xu_methods);
-
- d = PyModule_GetDict(m);
- port_error = PyErr_NewException(XENPKG ".PortError", NULL, NULL);
- PyDict_SetItemString(d, "PortError", port_error);
-}
+++ /dev/null
-
-from distutils.core import setup, Extension
-
-xu = Extension("xu",
- extra_compile_args = ["-fno-strict-aliasing"],
- include_dirs = ["../xc/lib",
- "../../xen/include/hypervisor-ifs",
- "../../linux-xen-sparse/include"],
- library_dirs = ["../xc/lib"],
- libraries = ["xc"],
- sources = ["lib/xu.c"])
-
-setup(name = "xu",
- version = "1.0",
- #packages = ["xend"],
- #package_dir = { "xend" : "lib" },
- ext_package = "xen.ext",
- ext_modules = [ xu ]
- )